Python里的那些“魔术方法”
什么是魔术方法?
在Python中,所有以双下划线__
包起来的方法,统称为Magic Method(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。或许在之前,你不知道这个概念,但我保证,只要你用过Python,那你一定在不经意间用过魔术方法。例如:对于两个字符串,你可能会用“+”号把他们连起来,得到一个合起来之后的字符串:
1 | a = 'Hello, ' |
但是,按理说,“+”只能对于数使用,字符串之间是不能相加的,那为什么上面那段程序还能够运行呢?这就是魔术方法的功劳了。事实上,因为str类实现了__add__魔术方法,进而实现了运算符重载,所以我们可以通过“+”来实现字符串的拼接。
魔术方法在类或对象的某些事件触发后会自动执行,让类具有神奇的“魔力”。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。例如,如果我们想要实现一个自己的字符串类,在两个长度相等的全是字母的字符串相加时,返回一个结果字符串,它的每个字符是两个字符串相应位置字母表排序更大的那个字母,那么我们就可以重写__add__魔术方法:
1 | class Mystr(str): |
常用的魔术方法
1. 初始化方法____init____
1 | 触发机制:实例化对象之后立即触发 |
2. 获取对象长度__len__
1 | 触发时机:使用len(对象) 的时候触发 |
3. 构造对象的字符串表示__str__与__repr__
1 | 触发时机:__str__:使用print(对象)或者str(对象),__repr__:repr(对象)的时候触发 |
未完待续……
魔术方法大全
方法名 | 参数列表 | 调用时机 | 返回值类型 | 备注 |
---|---|---|---|---|
__repr__ |
self |
当调用repr() 函数时 |
str |
返回值应为重建该对象的Python表达式(如果可能),或包含其他信息的字符串<...> |
__str__ |
self |
当调用str() 函数时 |
str |
调用print() 等其他函数时会隐式调用__str__() ,当不存在__str__() 时会自动调用__repr__() |
__format__ |
self, format_spec |
当调用format() 函数时 |
str |
object.__format__(x, '') 等价于str(x) |
__bytes__ |
self |
当调用bytes() 函数时 |
bytes |
返回值是对象的字节表示 |
__bool__ |
self |
调用bool() 函数时 |
bool |
当__bool__ 函数没有定义时,会隐式 调用__len__ ,如果__len__ 也没有 定义,则返回True |
__complex__ |
self |
调用commplex() 函数时 |
complex |
|
__int__ |
self |
调用int() 函数时 |
int |
|
__float__ |
self |
调用float() 函数时 |
float |
|
__hash__ |
self |
调用hash() |
函数时 | hash() 函数将__hash__() 的返回值 截断到Py_ssize_t 的范围内,64位系 统下Py_ssize_t 为8字节;set 等类 型的操作也会调用对象的__hash__ 函 数 |
__index__ |
self |
调用operator.index() 或Python需要整数值时 |
int |
当__int__ 、__float__ 、 __complex__ 没有实现时,这些函数隐式地调用__index__ |
__len__ |
self |
调用len() 函数时 |
int |
返回值必须为非负整数,在CPython中返回值不能超过sys.maxsize 中定义的值,否则len() 等函数会抛出OverflowError 等异常 |
__getitemm__ |
self, key |
使用[] 运算符时(右值) |
key 可以为合法的数组下标,也可以是反向的下标,也可以是序列的切片,该函数应在key 类型不对应时抛出TypeError ,key 超出范围时抛出IndexError 或KeyError (对于映射类型) |
|
__setitem__ |
self, key, value |
使用[] 运算符时(左值) |
None |
key 参数的取值及异常处理与__getitem__ 函数相同 |
__delitem__ |
self, key |
使用del 删除序列中的元素时 |
None |
对于不可删除的序列或映射,无需实现该函数,其他同__getitem__ |
__contains__ |
self, item |
使用in 作为运算符时 |
bool |
对于映射类型,__contains__ 接收的item 参数对应映射的key 部分而不是value 部分。若没有定义该函数,Python首先通过__iter__ 进行查找,其次使用__getitem__ 进行查找 |
__iter__ |
self |
调用iter() 函数或使用循环时 |
返回值应为可迭代对象,对于可迭代对象,__iter__ 函数返回自身 |
|
__reversed__ |
self |
调用reversed() 函数时 |
返回值应为可迭代对象,且是原序列的逆序 | |
__next__ |
self |
调用next() 函数时 |
返回可迭代对象中的下一个元素,当到达最后一个元素时抛出StopIteration |
|
__call__ |
self, *args, **kwargs |
当对象以函数的方式被调用时 | 定义了__call__ 方法的对象属于typing.Callable 类型 |
|
__enter__ |
self |
使用with 关键词声明上下文时 |
Any |
返回值分配给as 关键词指明的对象 |
__exit__ |
self, exc_type, exc_value, traceback |
离开with 块时 |
Any |
若with 块执行过程中没有出现异常,则exc_type, exc_value, traceback 参数均为None ,否则exit 块可以对异常进行处理 |
__new__ |
cls[, ...] |
创建类实例时 | Any |
__new__ 为静态方法且先于__init__ 执行,__new__ 的其余参数会传递给__init__ 。若__new__ 返回的类型与创建的类型不对应,则不会执行__init__ |
__init__ |
self, ... |
初始化类实例时 | None |
若基类定义了__init__ ,则在子类的__init__ 中必须有super().__init() 的显式调用 |
__del__ |
self |
对象销毁时 | None |
当对象的引用计数减为0时,对象才可能被删除 |
__getattribute__ |
self, name |
使用self.name 访问对象的属性时 |
Any |
为避免无限递归,子类的__getattribute__ 方法的实现中必须包含父类的__getattribute__ 方法调用 |
__getattr__ |
self, name |
使用self.name 访问对象的不存在属性或__getattribute__ 函数抛出AttributeError 异常 |
Any |
当__getattribute__ 正常执行时__getattr__ 不会执行 |
__setattr__ |
self, name, value |
使用self.name 设置属性的值时 |
None |
当试图通过__setattr__ 向对象设置属性值时必须通过类型的__setattr__ 方法进行设置 |
__delattr__ |
self, name |
执行del self.name 时 |
None |
仅当del self.name 语句有意义时,才需要实现该方法 |
__dir__ |
self |
执行dir() 函数时 |
Sequence |
dir() 会自动进行排序处理 |
运算符重载相关的魔术方法:
描述 | 方法名 | 运算符 |
---|---|---|
取负 | __neg__ |
- |
取正 | __pos__ |
+ |
绝对值 | __abs__ |
abs() |
小于 | __lt__ |
< |
小于等于 | __le__ |
<= |
等于 | __eq__ |
== |
不等于 | __ne__ |
!= |
大于 | __gt__ |
> |
大于等于 | __ge__ |
>= |
相加 | __add__ |
+ |
相减 | __sub__ |
- |
相乘 | __mul__ |
* |
实数除 | __truediv__ |
/ |
整数除 | __floordiv__ |
// |
取余 | __mod__ |
% |
整数除+取余 | __divmod__ |
divmod() |
乘方 | __pow__ |
** |
取整 | __round__ |
round() |
按位取反 | __invert__ |
~ |
左移 | __lshift__ |
<< |
右移 | __rshift__ |
>> |
按位与 | __and__ |
& |
按位或 | __or__ |
` |
按位异或 | __xor__ |
^ |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Chao Pang的个人主页!
评论