Property and __getattr__ compatibility issue with AttributeError
As mentioned by @asmeurer, the solution by @mguijarr calls prop
twice. When prop
first runs, it raises an AttributeError which triggers __getattr__
. Then self.__getattribute__(attr)
triggers prop
again, finally resulting in the desired exception.
BETTER ANSWER:
Here we are better off replacing __getattribute__
instead of __getattr__
. It gives us more control since __getattribute__
is invoked on all attribute access. In contrast, __getattr__
is only called when there has already been an AttributeError
, and it doesn't give us access to that original error.
class A(object):
def __getattribute__(self, attr):
try:
return super().__getattribute__(attr)
except AttributeError as e:
if not attr.startswith("ignore_"):
raise e
@property
def prop(self):
print("hi")
return self.some_typo
To explain, since A
subclasses object
in this case, super().__getattribute__(attr)
is equivalent to object.__getattribute__(self, attr)
. That reads a
's underlying object
attribute, avoiding the infinite recursion had we instead used self.__getattribute__(attr)
.
In case of AttributeError
, we have full control to either fail or reraise, and reraising gives a sensible error message.
You can just raise a better exception message:
class A(object):
def __getattr__(self, attr):
if not attr.startswith("ignore_"):
raise AttributeError("%r object has not attribute %r" % (self.__class__.__name__, attr))
@property
def prop(self):
return self.some_typo
a=A()
a.ignore_this
a.prop
EDIT: calling __getattribute__
from object base class solves the problem
class A(object):
def __getattr__(self, attr):
if not attr.startswith("ignore_"):
return self.__getattribute__(attr)
@property
def prop(self):
return self.some_typo