Using __getattr__ and property
Today I wasted a lot of time trying to figure out why a class using both a __getattr__ and a property mysteriously failed. The short version is: Make sure you don't raise an AttributeError in the property.fget()
The start point of this horrible voyage was a class which looked roughly like this:
class Foo(object):
def __getattr__(self, name):
return self._container.get(name, 'some_default')
@property
def foo(self):
val = self._container.get(foo)
if test(val):
return some_helper(val)
return val
This sees fine enough. Only it turns out that some_helper()
raised an AttributeError for some invalid input. Certainly reasonable since it was never meant to deal with incorrect input, that was meant to have been sanitised already (that was a bug in the caller which was actually just an incorrect unittest). The main gotcha was that it seems that python doesn't just check whether a "foo" is present in all the relevant __dict__
's along the mro. Instead it seems to use getattr(inst, "foo")
and then delegate to __getattr__()
if it gets an AttributeError. Now suddenly finding a bug in some_helper()
has turned into a puzzling question as to why __getattr__()
was called.
Personally I can't see why it doesn't use the mro to statically look up the required object instead of using the AttributeError-swallowing approach. But maybe there's a good reason.