Search code examples
pythonpython-3.xgetattributepython-datamodel

Why doesn't str() use __getattribute__ to get __str__ and how to produce the effect?


When I call str() on an object that has an overloaded __getattribute__ method it doesn't seem to use it and instead calls __str__ directly. Is there some other functionality I should be modifying or way to get it to use __getattribute__? If I overload __str__ directly it behaves as expected, but that isn't ideal for my needs.

class A(object):
    def __getattribute__(self, attr):
        if attr == "__str__":
            return lambda: "Hello"
        return object.__getattribute__(self, attr)

x = A()

print(x)
print(str(x))
print(x.__str__())

Output:
<main.A object at 0x000001FDF7AEA760>
<main.A object at 0x000001FDF7AEA760>
Hello

Expected Output:
Hello
Hello
Hello


Solution

  • Yes, this is documented behavior:

    This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions.

    And here:

    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

    ...

    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...

    ...

    As to why:

    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).