Don’t use Python’s hasattr() unless you’re writing Python 3-only code and understand how it works.

hasattr() is a common topic in Python code reviews. So instead of producing gists for each one, here once and for all:

Do not:

if hasattr(x, "y"): print(x.y) else: print("no y!")

Do instead:

try: print(x.y) except AttributeError: print("no y!")

or:

y = getattr(x, "y", None) if y is not None: print(y) else: print("no y!")

Especially, if you’re handling classes that aren’t your own.

hasattr() is not faster than getattr() since it goes through the exactly same lookup process and then throws away the result.

Why?

It might seem similar and the extra lines is annoying, but using hasattr() on Python 2 is close to writing:

try: print(x.y) except: print("no y!")

Which is almost never what you want because it shadows errors in properties:

>>> class C(object): ... @property ... def y(self): ... 0/0 ... >>> hasattr(C(), "y") False

Since in third party classes you can’t know whether an attribute is a property (or becomes one through an update after months or years), this is dangerous.

Do you think that’s no big deal? Check out this glowing testimonial! Another visible implication is that using hasattr() on properties does execute their getter function which makes the name misleading.

Python 3 gets it right:

>>> class C: ... @property ... def y(self): ... 0/0 ... >>> hasattr(C(), "y") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in y ZeroDivisionError: division by zero

Which makes it another edge case when writing hybrid code for both Python 2 and 3. But, would you expect hasattr() to raise that error?

The observant reader might ask, what about AttributeError s? And indeed: there’s no way to distinguish an AttributeError that is caused by a missing attribute and an AttributeError that is caused by a buggy property. The outlined approaches reduce your possible errors to only that one and avoid confusing differences in behavior between Python 2 and 3.

For your own code, you could still use hasattr() of course. But you’d have to keep track of it, remember to fix it if your classes change. This all adds unnecessary mental burden just to save some typing.

P.S. Yeah the title changed. Originally I really wrote this article so I can point people to it in discussions. I never expected it to hit #1 on Hacker News and I agree that “Considered Harmful” is getting old.

I just didn’t spend too much time worrying about it while hacking it together between getting up and leaving for work; it simply was the first thing that popped into my mind. I didn’t rename it right away as it may have confused people but now the dust has settled, it’s time to move on.