2

In the rare cases that an object's __getattribute__ method must be overridden, a common mistake is to try and return the attribute in question like so:

class WrongWay:
    def __getattribute__(self, name):
        # Custom functionality goes here
        return self.__dict__[name]

This code always yields a RuntimeError due to a recursive loop, since self.__dict__ is in itself an attribute reference that calls upon the same __getattribute__ method.

According to this answer, the correct solution to this problem is to replace last line with:

...
        return super().__getattribute__(self, name) # Defer responsibility to the superclass

This solution works when run through the Python 3 interpreter, but it also seems to violate __getattribute__'s promised functionality. Even if the superclass chain is traversed up to object, at the end of the line somebody will eventually have to return self.something, and by definition that attribute reference must first get through the child's __getattribute__ method.

How does Python get around this recursion issue? In object.__getattribute__, how is anything returned without looping into another request?

Community
  • 1
  • 1
RNanoware
  • 551
  • 6
  • 16
  • I think you meant `super().__getattribute__(name)`, not `super().__getattribute__(self, name)` – wim Aug 04 '16 at 18:57
  • 1
    Anyway, I won't hammer your question because it's an interesting and well written one, but here's a possible duplicate http://stackoverflow.com/q/13538324/674039 – wim Aug 04 '16 at 19:05
  • @wim Indeed, my question is a duplicate! My apologies; I had tried hard to ensure this question wouldn't add clutter to the site. I will look up how to mark the question as a duplicate. – RNanoware Aug 04 '16 at 21:32

1 Answers1

2

at the end of the line somebody will eventually have to return self.something, and by definition that attribute reference must first get through the child's __getattribute__() method.

That's not correct. object.__getattribute__ is not defined as returning self.anything, and it does not respect descendant class implementations of __getattribute__. object.__getattribute__ is the default attribute access implementation, and it always performs its job through the default attribute access mechanism.

Similarly, object.__eq__ is not defined as returning self == other_thing, and it does not respect descendant class implementations of __eq__. object.__str__ is not defined as returning str(self), and it does not respect descendant class implementations of __str__. object's methods are the default implementations of those methods, and they always do the default thing.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Thank you for correcting me! So, to clarify, the "default attribute access mechanism" you mention is only elucidated in Python's C implementation? I was under the false impression that any "magic method" would still be defined under Python's syntax and constraints, therefore greatly complicating `__getattribute__`'s strategy. – RNanoware Aug 04 '16 at 21:23
  • 2
    @RNanoware: If you want to take a look, it's [`PyObject_GenericGetAttr`](https://hg.python.org/cpython/file/3.5/Objects/object.c#l1116) in `Objects/object.c`. – user2357112 Aug 04 '16 at 21:44