你刚刚创建了一个类。你创建了一个 __init__
方法。现在怎么办?
Python 包含大量的 dunder 方法("双下划线 "方法),它们允许我们深度定制我们的自定义类与 Python 的许多特性交互的方式。您可以为您的类添加哪些 dunder 双下划线方法,使它对使用它的其他 Python 程序员友好?
让我们来看看 Python 中的各种种 dunder 双下划线方法,重点是每种方法在什么情况下有用。
请注意,Python 文档将这些方法称为特殊方法,并指出了同义词 "magic method",但很少使用 "dunder method "一词。然而,"dunder 双下划线方法 "是一个相当常见的 Python 口语,正如我的非官方 Python 词汇表所指出的。
您可以使用散布在本页中的链接来获取任何特定 dunder 双下划线方法的详细信息。有关所有 dunder 双下划线方法的列表,请参阅最后一节中的小抄。
大多数类都应该有 3 个 dunder 方法:__init__
、__repr__
和__eq__
。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
T(a, b=3)
|
T.__init__(x, a, b=3)
|
None
|
repr(x)
|
x.__repr__()
|
str
|
x == y
|
x.__eq__(y)
|
Typically
bool
|
__init__
方法是初始化器(不要与构造函数混淆),__repr__
方法自定义对象的字符串表示形式,__eq__
方法自定义对象相等的含义。
__repr__
方法在 Python REPL 和调试时特别有用。
除了 __eq__
方法外,Python 还有另外两个 dunder 方法,用于确定对象相对于其他对象的 "值"。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
x == y
|
x.__eq__(y)
|
Typically
bool
|
x != y
|
x.__ne__(y)
|
Typically
bool
|
hash(x)
|
x.__hash__()
|
int
|
Python 的 __eq__
方法通常返回 True
、False
或 NotImplemented
(如果对象无法比较)。缺省的 __eq__
实现依赖于 is
操作符,它会检查同一性。
__ne__
的默认实现调用 __eq__
并否定给出的布尔返回值(如果 __eq__
否定了布尔返回值,则返回 NotImplemented
)。这种默认行为通常 "足够好",所以你几乎看不到__ne__
的实现。
Hashable 对象可以用作字典中的键或集合中的值。Python 中的所有对象默认都是可散列的,但如果您编写了自定义的 __eq__
方法,那么如果没有自定义的 __hash__
方法,您的对象就不是可散列的。但是对象的哈希值必须永不改变,否则就会发生不好的事情,所以通常只有不可变对象才会实现 __hash__
。
要实现相等检查,请参见 Python 中的 __eq__
。要实
Python 的比较运算符 (<
, >
, <=
, >=
) 也都可以用 dunder 方法重载。比较运算符也为依赖于对象相对排序的函数提供了动力,如 sorted
、min
和 max
。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
<
|
__lt__
|
Typically
bool
|
>
|
__gt__
|
Typically
bool
|
<=
|
__le__
|
Typically
bool
|
>=
|
__ge__
|
Typically
bool
|
如果您打算以典型的方式实现所有这些操作符(其中 x < y
与要求 y > x
相同),那么 Python 的 functools
模块中的
total_ordering
decorator 就会派上用场。
Python 有许多将对象转换为不同类型的 dunder 方法。
函数 | Dunder 方法调用 | 返回 |
---|---|---|
str(x)
|
x.__str__()
|
str
|
bool(x)
|
x.__bool__()
|
bool
|
int(x)
|
x.__int__()
|
int
|
float(x)
|
x.__float__()
|
float
|
bytes(x)
|
x.__bytes__()
|
bytes
|
complex(x)
|
x.__complex__()
|
complex
|
f"{x:s}"
|
x.__format__(s)
|
str
|
repr(x)
|
x.__repr__()
|
str
|
__bool__ 函数用于真实性检查,但 __len__ 可作为备用。
如果需要创建一个类似于数字的对象(如 decimal.Decimal
或 fractions.Fraction
),就需要实现 __int__
, __float__
和 __complex__
函数,以便将对象转换为其他数字。如果你想创建一个可以在内存视图中使用或可以转换为字节的对象,你需要一个 __bytes__
方法。
__format__
和 __repr__
方法是不同的字符串转换方法。大多数字符串转换依赖于 __str__
方法,但默认的 __str__
实现只是简单地调用 __repr__
方法。
所有 f-string
转换、str
类的 format
方法和内置 format
函数(很少使用)都使用 __format__
方法。该方法允许日期时间对象支持自定义格式规范。
上下文管理器是可以在 with
块中使用的对象。
使用 | Dunder 方法调用 | 返回 |
---|---|---|
with block enter |
x.__enter__()
|
A value given to
as
|
with block exit |
x.__exit__(exc_type, exc, traceback)
|
Truthy/falsey value |
有关上下文管理器的更多信息,请参阅 "什么是上下文管理器 "和 "创建上下文管理器"。
Collections(又称容器)本质上是数据结构或类似数据结构的对象。Lists, dictionaries, sets, strings和元组tuples都是集合collections的例子。
程序 | Dunder 方法调用 | Return Type | Implemented |
---|---|---|---|
len(x)
|
x.__len__()
|
integer | Very common |
iter(x)
|
x.__iter__()
|
iterator | Very common |
for item in x: ...
|
x.__iter__()
|
iterator | Very common |
x[a]
|
x.__getitem__(a)
|
any object | Common |
x[a] = b
|
x.__setitem__(a, b)
|
None | Common |
del x[a]
|
x.__delitem__(a)
|
None | Common |
a in x
|
x.__contains__(a)
|
bool | Common |
reversed(x)
|
x.__reversed__()
|
iterator | Common |
next(x)
|
x.__next__()
|
any object | Uncommon |
x[a]
|
x.__missing__(a)
|
any object | Uncommon |
operator.length_hint(x)
|
x.__length_hint__()
|
integer | Uncommon |
__iter__
方法用于 iter
函数和所有形式的迭代:for
循环、comprehensions、元组解包,以及使用 *
进行可迭代解包。
__iter__
方法是创建自定义可迭代器所必需的,而 __next__
方法则是创建自定义迭代器所必需的(这种情况比较少见)。除非其他类决定实现 __missing__
方法,否则 __missing__
方法只会被 dict
类自身调用。__length_hint__
方法为不支持 __len__
的结构提供一个长度猜测,以便更有效地预设列表或其他结构的大小。
另请参见:迭代器协议、实现 __len__
和实现 __getitem__
。
函数、类和所有其他可调用对象都依赖于 __call__
方法。
程序 | Dunder 方法调用 | Return Type |
---|---|---|
x(a, b=c)
|
x.__call__(a, b=c)
|
any object |
调用类时,会使用其元类metaclass的 __call__
方法。调用类实例时,使用该类的 __call__
方法。
有关可调用性的更多信息,请参见 Callables:Python 的 "函数 "有时也是类。
Python 的 dunder 方法经常被描述为 "运算符重载 "的工具。这种 "运算符重载 "大多以 Python 各种算术运算符的形式出现。
有两种方法可以分解算术运算符:
+
,
-
,
*
,
/
,
%
) 与位运算符 (e.g.
&
,
|
,
^
,
>>
,
~
)x + y
) 与一元运算符(在 1 个数值之前,如
+x
)数学运算符比位运算符更常见,二进制运算符比一元运算符更常见。
这些就是二进制数学算术运算符:
程序 | Left-Hand Method | Right-Hand Method | Description |
---|---|---|---|
x + y
|
__add__
|
__radd__
|
Add / Concatenate |
x - y
|
__sub__
|
__rsub__
|
Subtract |
x * y
|
__mul__
|
__rmul__
|
Multiply |
x / y
|
__truediv__
|
__rtruediv__
|
Divide |
%
|
__mod__
|
__rmod__
|
Modulo |
x // y
|
__floordiv__
|
__rfloordiv__
|
Integer division |
**
|
__pow__
|
__rpow__
|
Exponentiate |
x @ y
|
__matmul__
|
__rmatmul__
|
Matrix multiply |
每个运算符都包括左手和右手方法。如果 x.__add__(y)
返回 NotImplemented
,那么将尝试 y.__radd__(x)
。有关更多信息,请参见算术 Dunder 方法。
这些是二进制位运算符:
程序 | Left-Hand Method | Right-Hand Method | Description |
---|---|---|---|
x & y
|
__and__
|
__rand__
|
AND |
x | y
|
__or__
|
__ror__
|
OR |
x ^ y
|
__xor__
|
__rxor__
|
XOR |
x >> y
|
__rshift__
|
__rrshift__
|
Right-shift |
x << y
|
__lshift__
|
__rlshift__
|
Left-shift |
这些是 Python 的一元算术运算符:
程序 | Dunder Method | Variety | Description |
---|---|---|---|
-x
|
__neg__
|
Mathematical | Negate |
+x
|
__pos__
|
Bitwise | Affirm |
~x
|
__invert__
|
Bitwise | Invert |
一元 +
运算符通常没有任何作用,但有些对象会将其用于特定操作。例如,在 collections.Counter
对象上使用 +
会删除非正值。
Python 的算术运算符经常用于非算术目的:序列使用 +
来连接,*
来自连;集合使用 &
来交集,|
来联合,-
来非对称差值,^
来对称差值。算术运算符有时也会被重载,用于更有创意的用途。例如,pathlib.Path
对象使用 /
来创建子路径。
Python 包含许多用于 In-place 运算的 dunder 方法。如果您要创建一个支持任何算术运算的可变对象,您也需要实现相关的In-place dunder 方法。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
x += y
|
x.__iadd__(y)
|
Typically
self
|
x -= y
|
x.__isub__(y)
|
Typically
self
|
x *= y
|
x.__imul__(y)
|
Typically
self
|
x /= y
|
x.__itruediv__(y)
|
Typically
self
|
x %= y
|
x.__imod__(y)
|
Typically
self
|
x //= y
|
x.__ifloordiv__(y)
|
Typically
self
|
x **= y
|
x.__ipow__(y)
|
Typically
self
|
x @= y
|
x.__imatmul__(y)
|
Typically
self
|
x &= y
|
x.__iand__(y)
|
Typically
self
|
x |= y
|
x.__ior__(y)
|
Typically
self
|
x ^= y
|
x.__ixor__(y)
|
Typically
self
|
x >>= y
|
x.__irshift__(y)
|
Typically
self
|
x <<= y
|
x.__ilshift__(y)
|
Typically
self
|
Python 的所有二进制算术运算符都可以在增强赋值语句中使用,即在对一个对象执行操作的同时,使用一个运算符和 =
符号对该对象进行赋值。
由于可变对象为 in-place 运算实现了适当的 dunder 方法,因此对可变对象的增强赋值预计会对原始对象进行变异。
如果找不到用于 in-place 运算的 dunder 方法,Python 会在执行运算后进行赋值。不可变对象通常不实现 in-place 运算的 dunder 方法,因为它们应该返回一个新对象,而不是改变原来的对象。
Python 还为许多数学相关函数提供了 dunder 方法,包括内置函数和数学库中的一些函数。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
divmod(x, y)
|
x.__divmod__(y)
|
2-item tuple |
divmod(x, y)
|
y.__rdivmod__(x)
|
2-item tuple |
abs(x)
|
x.__abs__()
|
float
|
sequence[x]
|
x.__index__()
|
int
|
round(x)
|
x.__round__()
|
Number |
math.trunc(x)
|
x.__trunc__()
|
Number |
math.floor(x)
|
x.__floor__()
|
Number |
math.ceil(x)
|
x.__ceil__()
|
Number |
Python 的 divmod
函数同时执行整除 (//
) 和模数运算 (%
)。请注意,就像许多二进制算术运算符一样,如果 divmod
需要询问第二个参数来处理操作,它也会检查 __rvidmod__
方法。
__index__
方法用于制作类整数对象。该方法可以无损地转换为整数,而不像 __int__
可以进行 "有损 "的整数转换(例如从 float
转换为 int
)。它用于需要真正整数的操作,如切片、索引以及 bin
、hex
和 oct
函数(example)。
Python 甚至包含了控制访问、删除或赋值对象上的任何属性时会发生什么的 dunder 方法!
程序 | Dunder 方法调用 | 返回 |
---|---|---|
x.missing
|
x.__getattr__("missing")
|
Attribute value |
x.anything
|
x.__getattribute__("anything")
|
Attribute value |
x.thing = value
|
x.__setattr__("thing", value)
|
None
|
del x.thing
|
x.__delattr__("thing")
|
None
|
dir(x)
|
x.__dir__()
|
List of strings |
每次属性访问都会调用 __getattribute__
方法,而 __getattr__
方法只有在 Python 找不到给定属性时才会被调用。所有的方法调用和属性访问都会调用 __getattribute__
方法,因此正确地实现它是一个挑战(由于意外的递归)。
__dir__
方法应返回一个属性名可迭代器(字符串)。当 dir
函数调用 __dir__
时,它会把返回的可迭代项转换成一个排序列表(就像 sorted
所做的那样)。
内置的 getattr
、setattr
和 delattr
函数与同名的 dunder 方法相对应,但它们只用于动态属性访问(而不是所有属性访问)。
现在我们开始使用真正不寻常的 dunder 方法。Python 包含许多用于元编程相关特性的 dunder 方法。
Implemented on | 程序 | Dunder 方法调用 | 返回 |
---|---|---|---|
Metaclasses |
class T: ...
|
type(base).__prepare__()
|
mapping |
Metaclasses |
isinstance(x, T)
|
T.__instancecheck__(x)
|
bool
|
Metaclasses |
issubclass(U, T)
|
T.__subclasscheck__(U)
|
bool
|
Any class |
class U(T): ...
|
T.__init_subclass__(U)
|
None
|
Any class | (Called manually) |
T.__subclasses__()
|
list
|
Any class |
class U(x): ...
|
x.__mro_entries__([x])
|
tuple
|
Any class |
T[y]
|
T.__class_getitem__(y)
|
an item |
__prepare__
方法自定义用于类的初始命名空间的字典。该方法用于预先填充字典值或自定义字典类型(愚蠢的例子)。
__instancecheck__
和 __subclasscheck__
方法覆盖了 isinstance
和 issubclass
的功能。Python 的 ABC 使用这些方法来练习 goose typing(在类型检查时进行鸭式键入)。
__init_subclass__
方法允许类挂钩子类初始化 (示例)。类也有一个 __subclasses__
方法 (在它们的元类 metaclass上),但通常不会被重载。
Python 在类继承过程中会调用 __mro_entries__
方法来处理实际上不是类的基类。typing.NamedTuple
函数使用它来假装它是一个类 (参见此处)。
__class_getitem__
方法允许类可下标(其元类不需要 __getitem__
方法)。它通常用于启用花哨的类型注解(如 list[int]
)。
Descriptors描述符是一种对象,当附加到一个类时,可以挂钩访问该类上所附加的属性名。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
class T: x = U()
|
T.x.__set_name__(T, 'x')
|
None
|
t.x
|
T.x.__get__(t, T)
|
The value |
t.x = y
|
T.x.__set__(t, y)
|
None
|
del t.x
|
T.x.__delete__(t)
|
None
|
描述符协议主要是为了让 Python 的属性装饰器工作而存在的一个特性,尽管它也被许多第三方库所使用。
要实现一个低级的内存数组?您需要 Python 的buffer 协议。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
memoryview(x)
|
x.__buffer__(flags)
|
memoryview
|
del memoryview(x)
|
x.__release_buffer__(m)
|
None
|
当删除从 __buffer__
返回的 buffer 时,会调用 __release_buffer__
方法。
Python 的缓冲区协议通常用 C 语言实现,因为它针对的是低级对象。
想要实现异步上下文管理器?您需要这些 dunder 方法:
__aenter__
: 与
__enter__
, 类似,但它返回一个 awaitable 对象__aexit__
: 一样
__exit__
, 但它返回一个 awaitable 对象需要支持异步迭代?你需要这些 dunder 方法:
__aiter__
: 必须返回异步迭代器 iterator__anext__
: like
__next__
类似于__next__
或非异步迭代器,但它必须返回一个可 awaitable 对象,而且应该引发 StopAsyncIteration
而不是 StopIteration
。
需要创建自己的 awaitable 对象吗?你需要这个 dunder 方法:
__await__
: 返回一个迭代器 iterator我在自定义异步对象方面经验不多,所以请到别处了解更多详情。
最后几个 dunder 方法与对象的创建和销毁有关。
程序 | Dunder 方法调用 | 返回 |
---|---|---|
T(a, b=3)
|
T.__new__(T, a, b=3)
|
New instance (
x ) |
T(a, b=3)
|
T.__init__(x, a, b=3)
|
None
|
del x
|
x.__del__()
|
None
|
调用类会返回一个新的类实例,这要归功于 __new__
方法。__new__
方法是 Python 的构造函数方法,不过与许多编程语言中的构造函数不同,您几乎不应该定义自己的 __new__
方法。要控制对象的创建,应首选初始化器 (__init__
),而不是构造函数 (__new__
)。下面是一个奇怪的 __new__
例子。
你可以把 __del__
想象成一个 "析构 destructor"方法,尽管它实际上被称为 finalizer 方法。在一个对象被删除之前,它的 __del__
方法会被调用(示例)。文件实现了一个 __del__
方法,用于关闭文件和它可能链接到的任何二进制文件缓冲区。
一些标准库模块定义了自定义的 dunder 方法,这些方法在其他地方没有使用:
__post_init__
方法abc.ABC
类有一个
__subclasshook__
方法,
abc.ABCMeta
在其
__subclasscheck__
方法中调用了该方法(更多内容请参见 goose typing)__fspath__
方法,它以字符串形式返回文件路径copy
将使用
__copy__
和
__deepcopy__
方法,如果有的话。__getnewargs_ex__
或
__getargs__
, 尽管
__getstate__
和
__setstate__
可以进一步自定义,而
__reduce__
或
__reduce_ex__
则是更低级的方法sys.getsizeof
依靠
__sizeof__
方法来获取对象的大小(以字节为单位)除 Dunder 方法外,Python 还有许多非方法的 Dunder 属性。
下面是一些比较常见的 dunder 属性:
__name__
: name of a function, classes, or module__module__
: module name for a function or class__doc__
:
docstring for a function, class, or module__class__
: an object's class (call
Python's
type
function instead)__dict__
: most objects store their attributes here (see
where are attributes stored?)__slots__
: classes using this are more memory efficient than classes using
__dict__
__match_args__
: classes can define a tuple noting the significance of positional attributes when the class is used in structural pattern matching (
match
-
case
)__mro__
: a class's method resolution order used when for attribute lookups and
super()
calls__bases__
: the direct parent classes of a class__file__
: the file that defined the module object (though not always present!)__wrapped__
: functions decorated with
functools.wraps
use this to point to the original function__version__
: commonly used for noting the version of a package__all__
: modules can use this to customize the behavior of
from my_module import *
__debug__
: running Python with
-O
sets this to
False
and disables Python's
assert
statements这些只是比较常见的 Dunder 属性。下面还有一些: Here are some more:
__defaults__
,
__kwdefaults__
,
__code__
,
__globals__
, and
__closure__
__qualname__
,
__annotations__
, and
__type_params__
__func__
and
__self__
__loader__
,
__package__
,
__spec__
, and
__cached__
attributes__path__
attribute__traceback__
,
__notes__
,
__context__
,
__cause__
, and
__suppress_context__
__objclass__
__classcell__
weakref
module uses
__weakref__
__origin__
,
__args__
,
__parameters__
, and
__unpacked__
sys
module has
__stdout__
and
__stderr__
which point to the original
stdout
and
stderr
versions此外,各种标准库模块也使用这些 dunder 属性:__covariant__
、__contravariant__
、__infer_variance__
、__bound__
、__constraints__
。Python 有一个内置的 __import__
函数,但你不应该使用它(最好使用 importlib.import_module
),CPython 有一个 __builtins__
变量,它指向 buildins
模块(但这是一个实现细节,需要时应显式导入 buildins
)。另外,从 __future__
模块导入可以启用特定的 Python 功能标志,Python 会在软件包中查找 __main__
模块,使它们可以作为 CLI 脚本运行。
这只是你在 Python 中能找到的大部分 dunder 属性名 😵
这是所有 Python dunder 方法的分类,大致按照最常见的方法排序。下面指出了一些注意事项。
Category | 程序 | Dunder 方法调用 | 返回 |
---|---|---|---|
Object Creation |
x = T(a, b)
|
x.__init__(a, b)
|
None
|
Object Creation |
x = T(a, b)
|
T.__new__(T, a, b)
|
New instance (
x ) |
Finalizer |
del x (ish) |
x.__del__()
|
None
|
Comparisons |
x == y
|
x.__eq__(y)
|
Typically
bool
|
Comparisons |
x != y
|
x.__ne__(y)
|
Typically
bool
|
Comparisons |
x < y
|
x.__lt__(y)
|
Typically
bool
|
Comparisons |
x > y
|
x.__rt__(y)
|
Typically
bool
|
Comparisons |
x <= y
|
x.__le__(y)
|
Typically
bool
|
Comparisons |
x >= y
|
x.__ge__(y)
|
Typically
bool
|
Hashability |
hash(x)
|
x.__hash__()
|
int
|
Conversions |
repr(x)
|
x.__repr__()
|
Always
str
|
Conversions |
str(x)
|
x.__str__()
|
Always
str
|
Conversions |
bool(x)
|
x.__bool__()
|
Always
bool
|
Conversions |
int(x)
|
x.__int__()
|
Always
int
|
Conversions |
float(x)
|
x.__float__()
|
Always
float
|
Conversions |
bytes(x)
|
x.__bytes__()
|
Always
bytes
|
Conversions |
complex(x)
|
x.__complex__()
|
Always
complex
|
Conversions |
format(x, s)
|
x.__format__(s)
|
Always
str
|
Context Managers |
with x as c:
|
x.__enter__()
|
The
c object |
Context Managers |
with x as c:
|
x.__exit__()
|
Truthy/falsey value |
Collections |
len(x)
|
x.__len__()
|
int
|
Collections |
iter(x)
|
x.__iter__()
|
An iterator |
Collections |
x[a]
|
x.__getitem__(a)
|
|
Collections |
x[a] = b
|
x.__setitem__(a, b)
|
None
|
Collections |
del x[a]
|
x.__delitem__(a)
|
None
|
Collections |
a in x
|
x.__contains__(a)
|
bool
|
Collections |
reversed(x)
|
x.__reversed__()
|
An iterator |
Collections |
next(x)
|
x.__next__()
|
Next iterator item |
Collections |
x[a]
|
x.__missing__(a)
|
|
Collections |
x.__length_hint__()
|
int
|
|
Arithmetic |
x + y
|
x.__add__(y)
|
|
Arithmetic |
x + y
|
y.__radd__(x)
|
|
Arithmetic |
x - y
|
x.__sub__(y)
|
|
Arithmetic |
x - y
|
y.__rsub__(x)
|
|
Arithmetic |
x * y
|
x.__mul__(y)
|
|
Arithmetic |
x * y
|
y.__rmul__(x)
|
|
Arithmetic |
x / y
|
x.__truediv__(y)
|
|
Arithmetic |
x / y
|
y.__rtruediv__(x)
|
|
Arithmetic |
x % y
|
x.__mod__(y)
|
|
Arithmetic |
x % y
|
y.__rmod__(x)
|
|
Arithmetic |
x // y
|
x.__floordiv__(y)
|
|
Arithmetic |
x // y
|
y.__rfloordiv__(x)
|
|
Arithmetic |
x ** y
|
x.__pow__(y)
|
|
Arithmetic |
x ** y
|
y.__rpow__(x)
|
|
Arithmetic |
x @ y
|
x.__matmul__(y)
|
|
Arithmetic |
x @ y
|
y.__rmatmul__(x)
|
|
Arithmetic |
x & y
|
x.__and__(y)
|
|
Arithmetic |
x & y
|
y.__rand__(x)
|
|
Arithmetic |
x | y
|
x.__or__(y)
|
|
Arithmetic |
x | y
|
y.__ror__(x)
|
|
Arithmetic |
x ^ y
|
x.__xor__(y)
|
|
Arithmetic |
x ^ y
|
y.__rxor__(x)
|
|
Arithmetic |
x >> y
|
x.__rshift__(y)
|
|
Arithmetic |
x >> y
|
y.__rrshift__(x)
|
|
Arithmetic |
x << y
|
x.__lshift__(y)
|
|
Arithmetic |
x << y
|
y.__rlshift__(x)
|
|
Arithmetic |
-x
|
x.__neg__()
|
|
Arithmetic |
+x
|
x.__pos__()
|
|
Arithmetic |
~x
|
x.__invert__()
|
|
Math functions |
divmod(x, y)
|
x.__divmod__(y)
|
2-item tuple |
Math functions |
abs(x)
|
x.__abs__()
|
float
|
Math functions |
x.__index__()
|
int
|
|
Math functions |
round(x)
|
x.__round__()
|
Number |
Math functions |
math.trunc(x)
|
x.__trunc__()
|
Number |
Math functions |
math.floor(x)
|
x.__floor__()
|
Number |
Math functions |
math.ceil(x)
|
x.__ceil__()
|
Number |
Assignment |
x += y
|
x.__iadd__(y)
|
Typically
self
|
Assignment |
x -= y
|
x.__isub__(y)
|
Typically
self
|
Assignment |
x *= y
|
x.__imul__(y)
|
Typically
self
|
Assignment |
x /= y
|
x.__itruediv__(y)
|
Typically
self
|
Assignment |
x %= y
|
x.__imod__(y)
|
Typically
self
|
Assignment |
x //= y
|
x.__ifloordiv__(y)
|
Typically
self
|
Assignment |
x **= y
|
x.__ipow__(y)
|
Typically
self
|
Assignment |
x @= y
|
x.__imatmul__(y)
|
Typically
self
|
Assignment |
x &= y
|
x.__iand__(y)
|
Typically
self
|
Assignment |
x |= y
|
x.__ior__(y)
|
Typically
self
|
Assignment |
x ^= y
|
x.__ixor__(y)
|
Typically
self
|
Assignment |
x >>= y
|
x.__irshift__(y)
|
Typically
self
|
Assignment |
x <<= y
|
x.__ilshift__(y)
|
Typically
self
|
Attributes |
x.y
|
x.__getattribute__('y')
|
|
Attributes |
x.y
|
x.__getattr__('y')
|
|
Attributes |
x.y = z
|
x.__setattr__('y', z)
|
None
|
Attributes |
del x.y
|
x.__delattr__('y')
|
None
|
Attributes |
dir(x)
|
x.__dir__()
|
An iterable |
Descriptors |
class T: x = U()
|
T.x.__set_name__(T, 'x')
|
None
|
Descriptors |
t.x
|
T.x.__get__(t, T)
|
|
Descriptors |
t.x = y
|
T.x.__set__(t, y)
|
None
|
Descriptors |
del t.x
|
T.x.__delete__(t)
|
None
|
Class stuff |
class U(T): ...
|
T.__init_subclass__(U)
|
None
|
Class stuff |
class U(x): ...
|
x.__mro_entries__([x])
|
tuple
|
Class stuff |
T[y]
|
T.__class_getitem__(y)
|
|
Metaclasses |
class T: ...
|
type(base).__prepare__()
|
dict /mapping |
Metaclasses |
isinstance(x, T)
|
T.__instancecheck__(x)
|
bool
|
Metaclasses |
issubclass(U, T)
|
T.__subclasscheck__(U)
|
bool
|
Async |
await x (ish) |
x.__await__()
|
An iterator |
Async |
async with x:
|
x.__aenter__()
|
An awaitable |
Async |
async with x:
|
x.__aexit__()
|
An awaitable |
Async |
async for a in x:
|
x.__aiter__()
|
An awaitable |
Async |
async for a in x:
|
x.__anext__()
|
An awaitable |
Buffers |
memoryview(x)
|
x.__buffer__(flags)
|
memoryview
|
Buffers |
del memoryview(x)
|
x.__release_buffer__(m)
|
None
|
上表有一个轻微但一致的错误。大多数 dunder 方法实际上不是直接在对象上调用的,而是在对象的类型上调用的:type(x).__add__(x, y)
而不是 x.__add__(y)
。这种区别在元类方法中最为重要。
我还特意排除了特定于库的 dunder 方法(如 __post_init__
)和你不可能定义的 dunder 方法(如 __subclasses__
)。请参见下文。
Category | 程序 | Dunder 方法调用 | 返回 |
---|---|---|---|
Dataclasses |
x = T(a, b)
|
T.__post_init__(a, b)
|
None
|
Copying |
copy.copy(x)
|
x.__copy__()
|
New object |
Copying |
copy.deepcopy(x)
|
x.__deepcopy__(memo)
|
New object |
Pickling |
pickle.dumps(x)
|
x.__getnewargs__()
|
A 2-item tuple |
Pickling |
pickle.dumps(x)
|
x.__getnewargs_ex__()
|
A 2-item tuple |
Pickling |
pickle.dumps(x)
|
x.__getstate__()
|
A meaningful state |
Pickling |
pickle.dumps(x)
|
x.__reduce__()
|
A 2-6 item tuple |
Pickling |
pickle.dumps(x)
|
x.__reduce_ex__(4)
|
A 2-6 item tuple |
Pickling |
pickle.loads(b)
|
x.__setstate__(state)
|
None
|
pathlib |
os.fspath(x)
|
p.__fspath__()
|
str or
bytes
|
sys |
sys.getsizeof(x)
|
x.__sizeof__()
|
int (size in bytes) |
Class stuff | None? |
x.__subclasses__()
|
Subclasses iterable |
ABCs |
issubclass(U, T)
|
T.__subclasshook__(U)
|
bool
|
因此,Python 包含 103 个 "普通 "的 dunder 方法,12 个特定于库的 dunder 方法,以及至少 52 个不同类型的其他 dunder 属性。这就是超过 150 个独特的 __dunder__
名称!我不建议记住这些名称:让 Python 完成它的工作,并随时查找您需要实现/查找的 dunder 方法或属性。
请记住,你并不是要发明你自己的 dunder 双下划线方法。有时您会看到一些第三方库发明了自己的 dunder 双下划线方法,但我们并不鼓励这样做,而且如果用户遇到这样的方法并认为它们是 "真正的 "dunder 双下划线方法,他们会感到非常困惑。