前言
Python的魔法函数是指Python的类中,一系列函数名由双下划线包裹的函数。
笔者最初接触到魔法函数的使用是在Pytorch中,在Pytorch中的Dataset类中有这样的用法:
除了常见的__init__构造函数外,还有__getitem__和__len__函数。在之后的代码中,笔者并没有看到__getitem__和__len__函数的显示调用。那么这样的声明与定义有什么意义?
首先定义一个空类,并用dir
方法获取类中的所有方法(一个空类真的是空空如也吗?)
|
|
结果:
|
|
我们可以看到许多默认的方法。比如每一个类都有一个默认的__init__方法作为其构造函数。而如果想定义自己的构造函数,就需要显式地对构造函数进行定义。
下面结合实例来说明一些魔法函数的用处。
基本
__new__(cls[,args...])
一个对象实例化的时候所调用的第一个方法。
__init__(self[, args...])
默认的构造函数,用于类的初始化。
注:__init__和__new__的区别:
在一般情况下,我们在构造类时调用的是__init__,但实际上第一个被调用的方法是__new__。以下代码为证:
1 2 3 4 5 6 7 8 9
class Bar: def __new__(cls, num): print("use __new__ method") return super(Bar, cls).__new__(cls) def __init__(self, num): print("use __init__ method") self.num = num bar = Bar(1)
结果为:
1 2
use __new__ method use __init__ method
一般情况下,我们放心使用__init__方法进行对象的构造即可,只需大致理解__new__和__init__的区别即可:
__new__
:创建对象时调用,会返回当前对象的一个实例
__init__
:创建完对象后调用,对当前对象的一些实例初始化,无返回值
__str__(self)
定义使用print()时的行为。
__repr__(self)
与str方法类似,但更面向开发者。如果一个类同时定义str()和repr(),那么会优先使用str()。
注:str和repr的返回值必须为str
__call__(self[, args...])
像函数一样调用类的实例。可以接参数。
__get__(self)
定义用对象为其他成员赋值的行为。
__set__(self[,args...])
定义为其他数据类型为对象赋值时的行为。
__del__(self)
默认的析构函数。
代码实例:
|
|
运算符重载
Python的类中定义了大量一元运算符、二元运算符、类型转换运算符等。此处不再一一赘述。
函数 | 功能 |
---|---|
__lt__(self, other) |
定义小于号的行为:x < y 调用 x.lt(y) |
__le__(self, other) |
定义小于等于号的行为:x <= y 调用 x.le(y) |
__eq__(self, other) |
定义等于号的行为:x ` y 调用 x.eq(y) |
__ne__(self, other) |
定义不等号的行为:x != y 调用 x.ne(y) |
__gt__(self, other) |
定义大于号的行为:x > y 调用 x.gt(y) |
__ge__(self, other) |
定义大于等于号的行为:x >= y 调用 x.ge(y) |
__add__(self, other) |
定义加法的行为:+ |
__sub__(self, other) |
定义减法的行为:- |
__mul__(self, other) |
定义乘法的行为:* |
__truediv__(self, other) |
定义真除法的行为:/ |
__floordiv__(self, other) |
定义整数除法的行为:// |
__mod__(self, other) |
定义取模算法的行为:% |
__divmod__(self, other) |
定义当被 divmod() 调用时的行为 |
__pow__(self, other[, modulo]) |
定义当被 power() 调用或 ` 运算时的行为 |
__lshift__(self, other) |
定义按位左移位的行为:« |
__rshift__(self, other) |
定义按位右移位的行为:» |
__and__(self, other) |
定义按位与操作的行为:& |
__xor__(self, other) |
定义按位异或操作的行为:^ |
__or__(self, other) |
定义按位或操作的行为:| |
__radd__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rsub__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rmul__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rtruediv__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rfloordiv__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rmod__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rdivmod__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rpow__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rlshift__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rrshift__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rand__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__rxor__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__ror__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
__iadd__(self, other) |
定义赋值加法的行为:+= |
__isub__(self, other) |
定义赋值减法的行为:-= |
__imul__(self, other) |
定义赋值乘法的行为:*= |
__itruediv__(self, other) |
定义赋值真除法的行为:/= |
__ifloordiv__(self, other) |
定义赋值整数除法的行为://= |
__imod__(self, other) |
定义赋值取模算法的行为:%= |
__ipow__(self, other[, modulo]) |
定义赋值幂运算的行为:`= |
__ilshift__(self, other) |
定义赋值按位左移位的行为:«= |
__irshift__(self, other) |
定义赋值按位右移位的行为:»= |
__iand__(self, other) |
定义赋值按位与操作的行为:&= |
__ixor__(self, other) |
定义赋值按位异或操作的行为:^= |
__ior__(self, other) |
定义赋值按位或操作的行为:|= |
__pos__(self) |
定义正号的行为:+x |
__neg__(self) |
定义负号的行为:-x |
__abs__(self) |
定义当被 abs() 调用时的行为 |
__invert__(self) |
定义按位求反的行为:~x |
__complex__(self) |
定义当被 complex() 调用时的行为(需要返回恰当的值) |
__int__(self) |
定义当被 int() 调用时的行为(需要返回恰当的值) |
__float__(self) |
定义当被 float() 调用时的行为(需要返回恰当的值) |
__round__(self[, n]) |
定义当被 round() 调用时的行为(需要返回恰当的值) |
容器
假设对象名为foo:
__len__(self)
定义调用len()时的返回值。(必须为int)
__getitem__(self,index)
定义调用foo[index]的返回值。
__setitem__(self,index,value)
定义为foo[index]赋值为value的行为。
__delitem__(self, key)
删除指定索引对应的元素。
__contains__(self, item)
判断序列是否包含指定元素。
迭代
__iter__(self)
生成迭代对象时调用,返回值必须是对象自己。
__next__(self)
每一次for循环都调用该方法。
如果一个类实现了iter()和next()方法,那么就认为它是一个可迭代对象。
以下用一个简单的实例(简单的dataloader)说明上述函数的用法:
|
|
回头再看开头的那个pytorch程序,是不是就没那么难了呢?
后记
实际上Python的魔法函数远不止这些。感兴趣的读者可以参阅https://rszalski.github.io/magicmethods/