In a class I want to map call to inst.addr
to a value crated by calling inst.addr_fun()
, and thus created this code:
class Common:
...
def __getattr__(self, name):
if hasattr(self, '{}_fun'.format(name)):
return getattr(self, '{}_fun'.format(name))()
else:
raise AttributeError('attribute unknown in instance')
def addr_fun(self):
return 42
However, it results in recursion, since the getattr
calls __getattr__
, so I can't get access to the addr_fun
function.
How to get access to a named attribute inside the instance?
Python language refererence about __getattr__:
object.__getattr__(self, name)
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 over attribute access.
This means that __getattr__
is only called if no instance variable, no class attribute and no method with the same name are found.
So your code works for "addr". You will get infinite recursion for other names because hasattr()
also uses __getattr__
.
You should avoid using hasattr()
and getattr()
inside __getattr__
.
Instead you can use super().__getattribute__(name)
in a try-except
block that catches AttributeError
.
Please note that super().__getattribute__(name)
doesn't call __getattr__(name)
on parent classes. So if you want to support a class hierarchy in which __getattr__
may chain to the __getattr__
method of another class you would need to call super().__getattr__(name)
if super.__getattribute__()
failed.