The following is an issue I've observed in Python 3.8. Let's say I define a simple class:
class A:
@property
def b(self):
return self.c # should throw AttributeError
Accessing A().b
fails as expected (see below), but here's my issue:
>>> getattr(A(), 'b', 5)
5
Which essentially tells me that getattr()
is the equivalent of:
def my_getattr_b(obj, default):
try:
return obj.b
except AttributeError:
# catches ANY missing attribute, not just b!
return default
This makes me very nervous to use getattr
in my code, because it can lead to completely incorrect behavior on a buggy class if it "fails" silently. The "correct" behavior ought to be that the exception is re-raised. Is the only safe solution the following?
def safe_getattr(obj, attr, default):
if attr in dir(obj):
# this will properly raise an AttributeError if something besides attr is missing
return getattr(obj, attr)
else:
return default
This works as expected:
>>> A().b
[...]
AttributeError: 'A' object has no attribute 'c'
This does too:
>>> getattr(A(), 'b')
[...]
AttributeError: 'A' object has no attribute 'c'