为什么Python的bool builtin只看class级别的__bool__方法
Why does Python's bool builtin only look at the class-level __bool__ method
documentation 明确指出
When this method (__bool__
) is not defined, __len__()
is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__()
nor __bool__()
, all its instances are considered true.
粗体是我插入的,斜体是我的,但文字确实在那里。 class 必须包含该方法这一事实很容易被
测试
class A:
pass
a = A()
a.__bool__ = (lamda self: False).__get__(a, type(a))
print(bool(A()), bool(a))
如文档所述,结果是 True True
。覆盖 __len__
会产生相同的结果:
b = A()
b.__len__ = (lambda self: 0).__get__(b, type(b))
print(bool(A()), bool(b))
这与文档声称的完全一样。但是,我发现这背后的原因有点违反直觉。我知道 bool
内置函数不查看实例的方法,但我不明白为什么。了解内部工作原理的人知道为什么只有 class 级 __bool__
和 __len__
方法影响真实性而忽略实例级方法吗?
原因是how special methods are looked up。
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
...
The rationale behind this behaviour lies with a number of special methods such as __hash__()
and __repr__()
that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself.
...
In addition to bypassing any instance attributes in the interest of correctness, implicit special method lookup generally also bypasses the __getattribute__()
method even of the object’s metaclass.
...
Bypassing the __getattribute__()
machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).
documentation 明确指出
When this method (
__bool__
) is not defined,__len__()
is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither__len__()
nor__bool__()
, all its instances are considered true.
粗体是我插入的,斜体是我的,但文字确实在那里。 class 必须包含该方法这一事实很容易被
测试class A:
pass
a = A()
a.__bool__ = (lamda self: False).__get__(a, type(a))
print(bool(A()), bool(a))
如文档所述,结果是 True True
。覆盖 __len__
会产生相同的结果:
b = A()
b.__len__ = (lambda self: 0).__get__(b, type(b))
print(bool(A()), bool(b))
这与文档声称的完全一样。但是,我发现这背后的原因有点违反直觉。我知道 bool
内置函数不查看实例的方法,但我不明白为什么。了解内部工作原理的人知道为什么只有 class 级 __bool__
和 __len__
方法影响真实性而忽略实例级方法吗?
原因是how special methods are looked up。
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
...
The rationale behind this behaviour lies with a number of special methods such as
__hash__()
and__repr__()
that are implemented by all objects, including type objects. If the implicit lookup of these methods used the conventional lookup process, they would fail when invoked on the type object itself.
...
In addition to bypassing any instance attributes in the interest of correctness, implicit special method lookup generally also bypasses the
__getattribute__()
method even of the object’s metaclass.
...
Bypassing the
__getattribute__()
machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).