Python Attribute Access using __getattr__ and __getattribute__
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 anAttributeError
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 anAttributeError
. This method should return the (computed) attribute value or raise anAttributeError
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