How do I override the __getattr__
method of a class without breaking the default behavior?
Asked
Active
Viewed 1.1e+01k times
3 Answers
312
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)

Rod
- 52,748
- 3
- 38
- 55

Michael Williamson
- 11,308
- 4
- 37
- 33
-
Bah, your edit has the same thing I was showing in my answer, +1. – Mar 08 '10 at 23:51
-
14Cool, Python doesn't seem to like calling super's in `__getattr__` -- any ideas what to do? (`AttributeError: 'super' object has no attribute '__getattr__'`) – gatoatigrado Jun 11 '13 at 23:33
-
1Without seeing your code it's hard to tell, but that looks like none of your superclasses define __getattr__. – Colin vH Apr 11 '15 at 16:00
-
This works with hasattr also because: "This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not." https://docs.python.org/2/library/functions.html#hasattr – ShaBANG Mar 07 '18 at 17:13
-
5-1 This *does* modify default behavior. Now you have an `AttributeError` without the context of the attribute in the exception args. – wim Nov 26 '18 at 19:43
-
@wim what to do then? – Max Oct 04 '22 at 19:40
-
@Max Either of the other 2 answers show how to keep context here. Unfortunately O.P. accepted the bad answer, and it got stuck to the top all those years ago.. – wim Oct 04 '22 at 19:54
39
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

wim
- 338,267
- 99
- 616
- 750
-
Thanks for this. Just wanted to make sure I had the default message correct without digging around in the source. – ShawnFumo Nov 04 '13 at 17:48
-
4I think that `self.__class__.__name__` should be used instead of `self.__class__` in case the class overrides `__repr__` – Michael Scott Asato Cuthbert Jan 11 '16 at 20:46
-
4This is better than accepted answer, but it would be nice not to have to rewrite that code and potentially miss the upstream changes should the wording be modified or extra context added to the exception object in future. – wim Nov 26 '18 at 19:56
24
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'

José Luis
- 3,713
- 4
- 33
- 37
-
2@fed.pavlo are you sure? Maybe you mixed `__getattr__` and `__getattribute__`? – José Luis Sep 16 '16 at 07:41
-
-
3
-
Shouldn't it be `return super().__getattribute__(name) ` just in case you also have a `__getattribute__` method in this class. – pauleohare Feb 25 '22 at 14:06
-
@pauleohare Yes, you might be right. Otherwise the `Foo.__getattribute__` would be invoked multiple times, unnecessarily – wim Oct 04 '22 at 20:53