pythonoopgetattrgetattribute

Understanding the difference between __getattr__ and __getattribute__


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.


Solution

  • Some basics first.

    With objects, you need to deal with their 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 become getattr(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:

    class A(dict):
        def __getattr__(self, name):
           return self[name]
    a = A()
    # Now a.somekey will give a['somekey']
    

    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.