I have been reading lately some tweets and the python documentation about hasattr and it says:
hasattr(object, name)
The
The documentation does not encourage, the documentation just states the obvious. The hasattr
is implemented as such, and throwing an AttributeError
from a property getter can make it look like the attribute does not exist. This is an important detail, and that is why it is explicitly stated in the documentation. Consider for example this code:
class Spam(object):
sausages = False
@property
def eggs(self):
if self.sausages:
return 42
raise AttributeError("No eggs without sausages")
@property
def invalid(self):
return self.foobar
spam = Spam()
print(hasattr(Spam, 'eggs'))
print(hasattr(spam, 'eggs'))
spam.sausages = True
print(hasattr(spam, 'eggs'))
print(hasattr(spam, 'invalid'))
The result is
True
False
True
False
That is the Spam
class has a property descriptor for eggs
, but since the getter raises AttributeError
if not self.sausages
, then the instance of that class does not "hasattr
" eggs
.
Other than that, use hasattr
only when you don't need the value; if you need the value, use getattr
with 2 arguments and catch the exception, or 3 arguments, the third being a sensible default value.
The results using getattr()
(2.7.9):
>>> spam = Spam()
>>> print(getattr(Spam, 'eggs'))
<property object at 0x01E2A570>
>>> print(getattr(spam, 'eggs'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in eggs
AttributeError: No eggs without sausages
>>> spam.sausages = True
>>> print(getattr(spam, 'eggs'))
42
>>> print(getattr(spam, 'invalid'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in invalid
AttributeError: 'Spam' object has no attribute 'invalid'
>>>
Seems that hasattr
has a problem with swallowing exceptions (at least in Python 2.7), so probably is better to stay away from it until it's fixed.
Take, for instance, the following code:
>>> class Foo(object):
... @property
... def my_attr(self):
... raise ValueError('nope, nope, nope')
...
>>> bar = Foo()
>>> bar.my_attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>> hasattr(Foo, 'my_attr')
True
>>> hasattr(bar, 'my_attr')
False
>>> getattr(bar, 'my_attr', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>>