Avoiding infinite loops in __getattribute__
python, python-3.x
Solution
You seem to be under the impression that your implementation of `__getattribute__` is merely a hook, that if you provide it Python will call it, and otherwise the interpreter will do its normal magic directly.
That is not correct. When python looks up attributes on instances, `__getattribute__` is the main entry for all attribute access, and `object` provides the default implementation. Your implementation is thus overriding the original, and if your implementation provides no alternative means of returning attributes it fails. You cannot use attribute access in that method, since all attribute access to the instance (`self`) is channelled again through `type(self).__getattribute__(self, attr)`.
The best way around this is by calling the overridden original again. That's where `super(C, self).__getattribute__(attr)` comes in; you are asking the next class in the class-resolution order to take care of the attribute access for you.
Alternatively, you can call the unbound `object.__getattribute__()` method directly. The C implementation of this method is the final stop for attribute access (it has direct access to `__dict__` and is thus not bound to the same limitations).
Note that `super()` returns a proxy object that'll look up whatever method can be found next in the method-resolution ordered base classes. If no such method exists, it'll fail with an attribute error. It will never call the original method. Thus `Foo.bar()` looking up `super(Foo, self).bar` will either be a base-class implementation or an attribute error, never `Foo.bar` itself.
Problem
The method `__getattribute__` needs to be written carefully in order to avoid the infinite loop. For example: ``` class A: def __init__(self): self.x = 100 def __getattribute__(self, x): return self.x >>> a = A() >>> a.x # infinite looop RuntimeError: maximum recursion depth exceeded while calling a Python object class B: def __init__(self): self.x = 100 def __getattribute__(self, x): return self.__dict__[x] >>> b = B() >>> b.x # infinite looop RuntimeError: maximum recursion depth exceeded while calling a Python object ``` Hence we need to write the method in this way: ``` class C: def __init__(self): self.x = 100 def __getattribute__(self, x): # 1. error # AttributeError: type object 'object' has no attribute '__getattr__' # return object.__getattr__(self, x) # 2. works return object.__getattribute__(self, x) # 3. works too # return super().__getattribute__(x) ``` My question is why does `object.__getattribute__` method work? From where does `object` get the `__getattribute__` method? And if `object` does not have any `__getattribute__`, then we are just calling the same method on class `C` but via the super class. Why, then calling the method via super class does not result in an infinite loop?