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.