I am trying to understand the difference between __getattr__
and __getattribute__
, however, I am failing at it.
The answer to the Stack Overflow question Difference between __getattr__
vs __getattribute__
says:
__getattribute__
is invoked before looking at the actual attributes on the object, and so can be tricky to implement correctly. You can end up in infinite recursions very easily.
I have absolutely no idea what that means.
Then it goes on to say:
You almost certainly want
__getattr__
.
Why?
I read that if __getattribute__
fails, __getattr__
is called. So why are there two different methods doing the same thing? If my code implements the new style classes, what should I use?
I am looking for some code examples to clear this question. I have Googled to best of my ability, but the answers that I found don't discuss the problem thoroughly.
If there is any documentation, I am ready to read that.
I think the other answers have done a great job of explaining the difference between
__getattr__
and__getattribute__
, but one thing that might not be clear is why you would want to use__getattribute__
. The cool thing about__getattribute__
is that it essentially allows you to overload the dot when accessing a class. This allows you to customize how attributes are accessed at a low level. For instance, suppose I want to define a class where all methods that only take a self argument are treated as properties:And from the interactive interpreter:
Of course this is a silly example and you probably wouldn't ever want to do this, but it shows you the power you can get from overriding
__getattribute__
.Some basics first.
With objects, you need to deal with its attributes. Ordinarily we do
instance.attribute
. Sometimes we need more control (when we do not know the name of the attribute in advance).For example,
instance.attribute
would becomegetattr(instance, attribute_name)
. Using this model, we can get the attribute by supplying the attribute_name as a string.Use of
__getattr__
You can also tell a class how to deal with attributes which it doesn't explicitly manage and do that via
__getattr__
method.Python will call this method whenever you request an attribute that hasn't already been defined, so you can define what to do with it.
A classic use case:
Caveats and use of
__getattribute__
If you need to catch every attribute regardless whether it exists or not, use
__getattribute__
instead. The difference is that__getattr__
only gets called for attributes that don't actually exist. If you set an attribute directly, referencing that attribute will retrieve it without calling__getattr__
.__getattribute__
is called all the times.__getattribute__
is called whenever an attribute access occurs.This will cause infinite recursion. The culprit here is the line
return self.__dict__[attr]
. Let's pretend (It's close enough to the truth) that all attributes are stored inself.__dict__
and available by their name. The lineattempts to access the
a
attribute off
. This callsf.__getattribute__('a')
.__getattribute__
then tries to loadself.__dict__
.__dict__
is an attribute ofself == f
and so python callsf.__getattribute__('__dict__')
which again tries to access the attribute'__dict__
'. This is infinite recursion.If
__getattr__
had been used instead thenf
has ana
attribute.f.b
) then it would not have been called to find__dict__
because it's already there and__getattr__
is invoked only if all other methods of finding the attribute have failed.The 'correct' way to write the above class using
__getattribute__
issuper(Foo, self).__getattribute__(attr)
binds the__getattribute__
method of the 'nearest' superclass (formally, the next class in the class's Method Resolution Order, or MRO) to the current objectself
and then calls it and lets that do the work.All of this trouble is avoided by using
__getattr__
which lets Python do it's normal thing until an attribute isn't found. At that point, Python hands control over to your__getattr__
method and lets it come up with something.It's also worth noting that you can run into infinite recursion with
__getattr__
.I'll leave that one as an exercise.