I want to override the __getattr__ method on a class to do something fancy but I don’t want to break the default behavior.
What’s the correct way to do this?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Overriding __getattr__ should be fine — __getattr__ is only called as a last resort i.e. if there are no attributes in the instance that match the name. For instance, if you access foo.bar, then __getattr__ will only be called if foo has no attribute called bar. If the attribute is one you don’t want to handle, raise AttributeError:
class Foo(object):
def __getattr__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
raise AttributeError
However, unlike __getattr__, __getattribute__ will be called first (only works for new style classes i.e. those that inherit from object). In this case, you can preserve default behaviour like so:
class Foo(object):
def __getattribute__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
return object.__getattribute__(self, name)
Method 2
class A(object):
def __init__(self):
self.a = 42
def __getattr__(self, attr):
if attr in ["b", "c"]:
return 42
raise AttributeError("%r object has no attribute %r" %
(self.__class__.__name__, attr))
>>> a = A() >>> a.a 42 >>> a.b 42 >>> a.missing Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in __getattr__ AttributeError: 'A' object has no attribute 'missing' >>> hasattr(a, "b") True >>> hasattr(a, "missing") False
Method 3
To extend Michael answer, if you want to maintain the default behavior using __getattr__, you can do it like so:
class Foo(object):
def __getattr__(self, name):
if name == 'something':
return 42
# Default behaviour
return self.__getattribute__(name)
Now the exception message is more descriptive:
>>> foo.something 42 >>> foo.error Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in __getattr__ AttributeError: 'Foo' object has no attribute 'error'
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0