漫谈Python魔术方法,见过的没见过的都在这里了
漫谈Python魔术方法,见过的没见过的都在这里了
就说一下,不深入
假的一览
- 提到魔术方法,学过python都应该知道一些。至少你得会__init__吧。
- 在我之前写的博文中有很多都涉及魔术方法。比如
- 浅谈Python中的if,可能有你不知道的
,涉及
__bool__
和
__len__
- 浅谈Python中的in,可能有你不知道的
,涉及
__contains__
,
__iter__
,
__getitem__
- Python常见面试题007. 谈谈Python中__init__和__new__的区别
- 浅谈Python中的if,可能有你不知道的
- 在《Python源码剖析》中做了个简单的概括(侵删),但仍然是不全的
数据模型
https://docs.python.org/zh-cn/3.9/reference/datamodel.html#special-method-names
以3.9为例
- 最全的还是在官方(但仍然会有漏网之鱼)
- 我稍作整理,仅供参考
1. ★基本定制
方法 | 说明 |
---|---|
__init__(self[, ...])
|
所谓的初始化,在实例 (通过
__new__
) 被创建之后,返回调用者之前调用 |
__new__(cls[, ...])
|
调用以创建一个 cls 类的新实例 |
__del__(self)
|
在实例将被销毁时调用。 这还被称为终结器或析构器(不适当) |
__repr__(self)
|
由 repr() 内置函数调用以输出一个对象的“官方”字符串表示 |
__str__(self)
|
通过 str(object) 以及内置函数 format() 和 print() 调用以生成一个对象的“非正式”或格式良好的字符串表示 |
__bytes__(self)
|
通过 bytes 调用以生成一个对象的字节串表示 |
__format__(self,format_spec)
|
通过 format() 内置函数、扩展、格式化字符串字面值 的求值以及 str.format() 方法调用以生成一个对象的“格式化”字符串表示 |
__hash__(self)
|
通过内置函数 hash() 调用以对哈希集的成员进行操作,属于哈希集的类型包括 set、frozenset 以及 dict。
__hash__()
应该返回一个整数 |
__bool__(self)
|
调用此方法以实现真值检测以及内置的
bool()
操作;应该返回
False
或
True
|
2. 富比较方法
方法 | 说明 |
---|---|
__lt__(self, other)
|
小于 |
__le__(self, other)
|
小于等于 |
__eq__(self, other)
|
等于 |
__ne__(self, other)
|
不等于 |
__gt__(self, other)
|
大于 |
__ge__(self, other)
|
大于等于 |
3. ★自定义属性访问
方法 | 说明 |
---|---|
__getattr__(self, name)
|
当默认属性访问因引发 AttributeError 而失败时被调用 |
__getattribute__(self, name)
|
此方法会无条件地被调用以实现对类实例属性的访问 |
__setattr__(self, name, value)
|
此方法在一个属性被尝试赋值时被调用 |
__delattr__(self, name)
|
类似于
__setattr__()
但其作用为删除而非赋值 |
__dir__(self)
|
此方法会在对相应对象调用 dir() 时被调用 |
4. ★实现描述器
方法 | 说明 |
---|---|
__get__(self, instance, owner=None)
|
调用此方法以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问) |
__set__(self, instance, value)
|
用此方法以设置 instance 指定的所有者类的实例的属性为新值 value 。 |
__delete__(self, instance)
|
调用此方法以删除 instance 指定的所有者类的实例的属性。 |
__set_name__(self, owner, name)
|
在所有者类 owner 创建时被调用。描述器会被赋值给 name 。 |
5. 自定义类创建
方法 | 说明 |
---|---|
__init_subclass__(cls)
|
当所在类派生子类时此方法就会被调用 |
6. 自定义实例及子类检查
方法 | 说明 |
---|---|
__instancecheck__(self, instance)
|
如果 instance 应被视为 class 的一个(直接或间接)实例则返回真值 |
__subclasscheck__(self, subclass)
|
如果 subclass 应被视为 class 的一个(直接或间接)子类则返回真值 |
7. 模拟泛型类型
方法 | 说明 |
---|---|
__class_getitem__(cls, key)
|
按照 key 参数指定的类型返回一个表示泛型类的专门化对象。 |
- 当在类上定义时,
__class_getitem__()
会自动成为类方法。 因此,当它被定义时没有必要使用
@classmethod
来装饰。
8. ★模拟可调用对象
方法 | 说明 |
---|---|
__call__(self[, args...])
|
此方法会在实例作为一个函数被“调用”时被调用 |
9. ★模拟容器类型
方法 | 说明 |
---|---|
__len__(self)
|
调用此方法以实现内置函数 len()。应该返回对象的长度 |
__length_hint__(self)
|
调用此方法以实现 operator.length_hint()。 应该返回对象长度的估计值(可能大于或小于实际长度) |
__getitem__(self, key)
|
调用此方法以实现
self[key]
的取值(注:官文是未付,英文是evaluation) |
__setitem__(self, key, value)
|
调用此方法以实现向
self[key]
赋值 |
__delitem__(self, key)
|
调用此方法以实现
self[key]
的删除 |
__missing__(self, key)
|
此方法由 dict.
__getitem__()
在找不到字典中的键时调用以实现 dict 子类的 self[key] |
__iter__(self)
|
此方法在需要为容器创建迭代器时被调用 |
__reversed__(self)
|
此方法(如果存在)会被
reversed()
内置函数调用以实现逆向迭代 |
__contains__(self, item)
|
调用此方法以实现成员检测运算符in |
10. ★模拟数字类型
方法 | 说明 |
---|---|
__add__(self, other)
|
+ |
__sub__(self, other)
|
- |
__mul__(self, other)
|
* |
__matmul__(self, other)
|
@这个你可能没听过 |
__truediv__(self, other)
|
除法 / |
__floordiv__(self, other)
|
地板除 // |
__mod__(self, other)
|
取余 % |
__pow__(self, other[,modulo])
|
幂运算 ** |
__lshift__(self, other)
|
左移 << |
__rshift__(self, other)
|
右移 >> |
__and__(self, other)
|
& 与 |
__xor__(self, other)
|
^ 异或 |
__or__(self, other)
|
| 或 |
- 上面的方法再加个r又是另外一大类
方法 | 说明 |
---|---|
__radd__(self, other)
|
+ |
__rsub__(self, other)
|
- |
__rmul__(self, other)
|
* |
__rmatmul__(self, other)
|
@ |
` rtruediv (self, other) |
/ |
__rfloordiv__(self, other)
|
// |
__rmod__(self, other)
|
取余 % |
__rpow__(self, other[,modulo])
|
幂运算 ** |
__rlshift__(self, other)
|
左移 << |
__rrshift__(self, other)
|
右移 >> |
__rand__(self, other)
|
& |
__rxor__(self, other)
|
^ |
__ror__(self, other)
|
| |
调用这些方法来实现具有反射(交换)操作数的二进制算术运算 (
+
,
-
,
*
,
@
,
/
,
//
,
%
,
divmod()
,
pow()
,
**
,
<<
,
>>
,
&
,
^
,
|
)。这些成员函数仅会在左操作数不支持相应运算
3
且两个操作数类型不同时被调用。
4
例如,求表达式
x - y
的值,其中
y
是具有
__rsub__()
方法的类的一个实例,则当
x.__sub__(y)
返回
NotImplemented
时会调用
y.__rsub__(x)
。请注意三元版的
pow()
并不会尝试调用
__rpow__()
(因为强制转换规则会太过复杂)
- 加个i又是另外一套
方法 | 说明 |
---|---|
__iadd__(self, other)
|
+= |
__isub__(self, other)
|
-= |
__imul__(self, other)
|
*= |
__imatmul__(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)
|
|= |
- 调用上面这些方法来实现扩展算术赋值
- 数字是最多的
- 不光上面的,还要一些
方法 | 说明 |
---|---|
__neg__(self)
|
一元运算符 - |
__pos__(self)
|
一元运算符 + |
__abs__(self)
|
abs() |
__invert__(self)
|
一元运算符 ~ |
__complex__(self)
|
实现内置函数complex() |
__int__(self)
|
实现内置函数int() |
__float__(self)
|
实现内置函数float() |
__index__(self)
|
调用此方法以实现 operator.index() |
__round__(self[,ndigits])
|
实现内置函数round() |
__trunc__(self)
|
实现内置函数trunc() |
__floor__(self)
|
实现内置函数floor() |
__ceil__(self)
|
实现内置函数ceil() |
11. 上下文管理器
方法 | 说明 |
---|---|
__enter__(self)
|
进入与此对象相关的运行时上下文 |
__exit__(self, exc_type, exc_value, traceback)
|
退出关联到此对象的运行时上下文 |
12. 协程相关
可等待对象
方法 | 说明 |
---|---|
__await__(self)
|
awaitable 对象主要实现了该方法,它必须返回一个 iterator |
异步迭代器
方法 | 说明 |
---|---|
__aiter__(self)
|
必须返回一个 异步迭代器 对象 |
__anext__(self)
|
必须返回一个 可迭代对象 输出迭代器的下一结果值 |
异步上下文管理器
方法 | 说明 |
---|---|
__aenter__(self)
|
在语义上类似于
__enter__()
,仅有的区别是它必须返回一个 可等待对象 |
__aexit__(self)
|
在语义上类似于
__exit__()
,仅有的区别是它必须返回一个 可等待对象 |
00. 漏网之鱼
方法 | 说明 |
---|---|
__objclass__
|
会被
inspect
模块解读为指定此对象定义所在的类 |
__slots__
|
允许我们显式地声明数据成员(如特征属性)并禁止创建 dict 和 weakref |
__mro_entries__
|
|
__prepare__
|
|
__class__
|
|
__classcell__
|
说在最后
码农高天出了一个系列讲解魔术方法,推荐观看https://www.bilibili.com/video/BV1b84y1e7hG
流畅的python对魔术方法的讲解比较深入,贯穿全文,有一定难度,基础薄弱的谨慎
前面在哪里说过很多内置函数、操作、运算符的背后多数都是这些魔术方法的实现。
- with上下文管理器的背后是
__enter__(self)
和
__exit__(self, exc_type, exc_value, traceback)
- 多数的运算符背后都是的
10. 模式数字类型 - 内置函数如len的背后是
__len__
- with上下文管理器的背后是