views:

81

answers:

1

When writing concurrent/multithreaded code in Python, is it especially important to follow the "Easier to Ask for Forgiveness than Permission" (EAFP) idiom, rather than "Look Before You Leap" (LBYL)? Python's exceptionally dynamic nature means that almost anything (e.g., attribute removal) can happen between looking and leaping---if so, what's the point? For example, consider

# LBYL
if hasattr(foo, 'bar'):
    baz = foo.bar

versus

# EAFP
try:
    baz = foo.bar
except AttributeError:
    pass

In the LBYL example, the bar attribute could disappear from foo before the actual call to foo.bar is made, so do you gain anything from the check? If there's a risk the attribute might disappear, you need locks and/or try/except clauses anyway.

One possible argument here is that this example makes the extremely pessimistic assumption that "antagonistic code" is running that could yank the rug from under you at any moment. In most use cases, this is highly unlikely.

+1  A: 

Your thoughts are correct. Some additional points:

If the attribute exists most of the time, try:except: might be much faster than the LBYL idiom.

If you don't like the try: except: syntax, you can also write:

item = getattr(foo, 'bar', None)
if item is None:
    ....
else:
    ....
theller
+1: The performance has been beaten to death -- the try/except is generally faster. And more reliable. And the assumption about other threads is not "extremely pessimistic" -- it's essential to success.
S.Lott
I don't know if getattr is guaranteed to be atomic in CPython. The GIL might make it so, but it's probably not atomic in Jython or IronPython.Certainly the two-step LBYL hasattr above cannot be atomic.
George V. Reilly
good point, george. my guess is that on the inside, we've got an EAFP try-catch block that returns None if anything goes wrong
zweiterlinde