Today, I happened to forget the difference between __getattr__ and __getattribute__ methods and what they accomplish in Python?s Data Model.
So I am writing this story down to serve as a quick and simple reference for me and anyone interested.
I first studied the official documentation for __getattr__ and __getattribute__
__getattr__
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called. (This is an intentional asymmetry between __getattr__() and __setattr__().) This is done both for efficiency reasons and because otherwise __getattr__() would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__() method below for a way to actually get total control in new-style classes.
Source: Python Data Model : Customizing Attribute Access
__getattribute__
Called unconditionally to implement attribute accesses for instances of the class. If the class also defines __getattr__(), the latter will not be called unless __getattribute__() either calls it explicitly or raises an AttributeError. This method should return the (computed) attribute value or raise an AttributeError exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).
Source: Python Data Model : More Attribute Access for New Style Classes
After studying the official documentation, I wrote the following simple Python class that overrides the base class implementation and injected some print statements followed by calling base class methods.
class Yeah(object): def __init__(self, name): self.name = name # Gets called when an attribute is accessed def __getattribute__(self, item): print ‘__getattribute__ ‘, item # Calling the super class to avoid recursion return super(Yeah, self).__getattribute__(item) # Gets called when the item is not found via __getattribute__ def __getattr__(self, item): print ‘__getattr__ ‘, item return super(Yeah, self).__setattr__(item, ‘orphan’)
And then using an instance of the class above shined light on the mechanics of attribute access.
>> y1 = Yeah(‘yes’)>> y1.name__getattribute__ name’yes’>> y1.foo__getattribute__ foo__getattr__ foo>> y1.foo__getattribute__ foo’orphan’>> y1.goo__getattribute__ goo__getattr__ goo>> y1.__dict____getattribute__ __dict__{‘__members__’: ‘orphan’, ‘__methods__’: ‘orphan’, ‘foo’: ‘orphan’, ‘goo’: ‘orphan’, ‘name’: ‘yes’}
I think it is a bit more clear now. If it is not, let us discuss in the comments below.
Satish Goda
References
- https://stackoverflow.com/a/371833/1152323