Why does Python's bool builtin only look at the class-level __bool__ method [duplicate]
Asked Answered
E

1

1

The documentation clearly states that

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.

Bold is my insertion, italics is mine but the text is actually there. The fact that the class must contain the method is readily tested by

class A:
    pass

a = A()
a.__bool__ = (lamda self: False).__get__(a, type(a))

print(bool(A()), bool(a))

The result is True True, as the documentation claims. Overriding __len__ yields the same result:

b = A()
b.__len__ = (lambda self: 0).__get__(b, type(b))

print(bool(A()), bool(b))

This works exactly as the documentation claims it will. However, I find the reasoning behind this to be a little counter-intuitive. I understand that the bool builtin does not look at the methods of the instance, but I do not understand why. Does someone with a knowledge of the internal workings know why only the class-level __bool__ and __len__ methods affect truthiness while instance-level methods are ignored?

Exoteric answered 9/2, 2017 at 20:39 Comment(0)
D
2

The reason is 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).

Dorfman answered 9/2, 2017 at 21:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.