views:

1042

answers:

8
if hasattr(obj, 'attribute'):
    # do somthing

vs

try:
    # access obj.attribute
except AttributeError, e:
    # deal with AttributeError

Which should be preferred and why?

A: 

The first.

Shorter is better. Exceptions should be exceptional.

Unknown
Exceptions are very common in Python -- there's one at the end of every `for` statement, and `hasattr` uses one, too. However, "shorter is better" (and "simpler is better"!) DO apply, so the simpler, shorter, more-specific hasattr is indeed preferable.
Alex Martelli
@Alex just because the Python parser transforms those statements to have 1 doesn't mean its very common. There's a reason why they made that syntactic sugar: so you aren't stuck with the cruftiness of typing the try except block.
Unknown
If the exception is exceptional, then "explicit is better", and the original poster's 2nd option is better, I'd say…
EOL
+7  A: 

hasattr internally and rapidly performs the same task as the try/except block: it's a very specific, optimized, one-task tool and thus should be preferred, when applicable, to the very general-purpose alternative.

Alex Martelli
Except you still need the try/catch block to handle race conditions (if you are using threads).
Douglas Leeder
+3  A: 

If it's just one attribute you're testing, I'd say use hasattr. However, if you're doing several accesses to attributes which may or may not exist then using a try block may save you some typing.

n8gray
+6  A: 

I would say it depends on whether your function may accept objects without the attribute by design, e.g. if you have two callers to the function, one providing an object with the attribute and the other providing an object without it.

If the only case where you'll get an object without the attribute is due to some error, I would recommend using the exceptions mechanism even though it may be slower, because I believe it is a cleaner design.

Bottom line: I think it's a design and readability issue rather than an efficiency issue.

Roee Adler
+1 for insisting on why "try" has a meaning for people who read the code. :)
EOL
+1  A: 

From a practical point of view, in most languages using a conditional will always be consderably faster than handling an exception.

If you're wanting to handle the case of an attribute not existing somewhere outside of the current function, the exception is the better way to go. An indicator that you may want to be using an exception instead of a conditional is that the conditional merely sets a flag and aborts the current operation, and something elsewhere checks this flag and takes action based on that.

That said, as Rax Olgud points out, communication with others is one important attribute of code, and what you want to say by saying "this is an exceptional situation" rather than "this is is something I expect to happen" may be more important.

Curt Sampson
+1 for insisting on the fact that "try" can be interpreted as "this is an exceptional situation", compared to the conditional test. :)
EOL
+9  A: 

Any benches that illustrate difference in performance?

(I haven't enough reputation)

timeit it's your friend

$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "nonexistent")'
1000000 loops, best of 3: 1.87 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'hasattr(c, "a")'
1000000 loops, best of 3: 0.446 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
 c.a
except:
 pass'
1000000 loops, best of 3: 0.247 usec per loop
$ python -mtimeit -s 'class C(object): a = 4
c = C()' 'try:
 c.nonexistent
except:
 pass'
100000 loops, best of 3: 3.13 usec per loop
$

       |positive|negative
hasattr|  0.446 |  1.87 
try    |  0.247 |  3.13
ZeD
+1 for providing interesting, tangible numbers. In fact, the "try" is efficient when it contains the common case (i.e. when a Python exception is really exceptional).
EOL
+2  A: 

I'd suggest option 2. Option 1 has a race condition if some other thread is adding or removing the attribute.

Also python has an Idiom, that EAFP ('easier to ask forgiveness than permission') is better than LBYL ('look before you leap').

Douglas Leeder
A: 

If not having the attribute is not an error condition, the exception handling variant has a problem: it would catch also AttributeErrors that might come internally when accessing obj.attribute (for instance because attribute is a property so that accessing it calls some code).

UncleZeiv