Confused compare function :)

Chris Angelico rosuav at gmail.com
Thu Dec 6 10:34:28 CET 2012


On Thu, Dec 6, 2012 at 7:49 PM, Bruno Dupuis
<python.ml.bruno.dupuis at lisael.org> wrote:
>
> The point is Exceptions are made for error handling, not for normal
> workflow. I hate when i read that for example:
>
>     try:
>         do_stuff(mydict[k])
>     except KeyError:
>         pass
>
> (loads of them in many libraries and frameworks)
> instead of:
>
>     if k in mydict:
>         do_stuff(mydict[k])
>
> Note that the performances are better with the latter.
>

This is the age-old question of EAFP vs LBYL.

The check-first "Look Before You Leap" option has a small chance of
race condition. If something changes between the 'if' and the usage,
maybe from another thread or maybe a signal handler or perhaps some
object's __del__ method gets called or who knows what, you'll have a
problem.

Python's usual philosophy is that it's Easier to Ask Forgiveness than
Permission. Just do it, and jump out if you can't. This technique
plays *very* nicely with generic handlers. For instance, at work I
wrote an HTTP daemon that's supposed to receive XML-encoded POST data
with a particular structure. The handler function (called once for
every HTTP request) looks something like this, in Pythonesque
pseudocode:

def handler(req):
  try:
    msg = parse_xml(req.body) # returns a dict of dicts/lists/strings
    stuff = msg["soapenv:Envelope"]["soapenv:Body"]["GetItemTransactionsResponse"]
    sig = stuff["Item"]["ApplicationData"]
    if sig.does.not.match(): return "Bad request"
    sscanf(sig,"FOO %d %d %d",account,table,row)
    accountdata[account][table][row] = 1
    return "Done and successful."
  except:
    log_error_to_stderr()
    return "Done."

I don't particularly care _what_ the error is. Most of the time, I
won't even bother to look at the log file (it's run via an Upstart
job, and stderr is redirected to a file), but if I'm having problems,
I can go check. Generally, exceptions thrown by that code are the
result of malformed info packets; since it's basic HTTP, it's easy for
anyone to send a request in, and I don't care to see those errors
logged. In fact, the logging to stderr can even get commented out in
production, and used only when there's actually a problem being
diagnosed.

To try to handle all possible errors in that code by LBLY, I would
need to pepper the code with conditions and an appropriate 'return'
statement (and, though the pseudo-code has the function returning a
string, the actual code involves an explicit "send this response"
call). Plus, I'd need to predict every possible failure. With EAFP,
all I need is one simple "catch" handler for the whole block of code,
and I can easily eyeball just a few function exit points to see that
an appropriate HTTP response will always be sent.

Each has its place.

ChrisA



More information about the Python-list mailing list