EAFP vs LBYL (was Re: A little disappointed so far)

Alex Martelli aleax at aleax.it
Mon May 19 11:51:14 CEST 2003


<posted & mailed>

Graham Nicholls wrote:
   ...
>> os.path.isfile(filename)
> Aha, thanks.
>> 
>> But Alex will probably trundle by in a moment to tell you that in many
>> cases, you don't want to do that.  Python's powerful exception handling
>> system means that most of the time you just do:
>> 
>> try:
>>     f = file(filename)
>> except IOError:
>>     <handle exception>
>> 
> I guess thats reasonably succinct.

The reference to me is probably in connection to the fact that I'm one
of the heartiest paladin of the latter approach to the detection and
handling of anomalous situation ("it's easier to ask forgiveness than
permission" aka EAFP) over the former ("look before you leap" aka LBYL),
even though in the Python Cookbook you will find a recipe of mine, which
I named "accurate LBYL", showing some tricks that are occasionally
useful to inject some minor aspects of LBYL in an overall EAFP strategy
(and some mention of why that might be useful in some strange cases).


> So, generally is it the "Python Way" to try things and handle the
> exceptions, as in try... except, or to run os.path.isfile ?

The best approach in any language is almost invariably EAFP.  Rear Admiral
Grace Murray Hopper, who coined the "EAFP" motto, is best known as the
inventor of Cobol, and I doubt she even ever heard of Python before
her death.  But she WAS an exceedingly practical as well as inventive
person, and that is by far sufficient to justify EAFP.  [Note: researching
the "EAFP" motto's history, I've found incomplete and contradictory leads
to its possibly being in use in some Navy and/or Marine units, perhaps
before Hopper's adoption of it -- in any case, Hopper can surely be credited
as first to apply the motto to *computers*, as she was a pioneer in the
computer field].  Python's claim to distinction here is just that it makes
EAFP easier and more natural to use than any other language I know:-).

> Are there good reasons for this? I'm not a computer scientist, and I am
> beginning to suspect that Python is a CS language.  Is that unfair?  (That
> implies that being a CS language is a bad thing, which I'm not at all sure
> of :-)

"Being a CS language" is a wonderful thing in its own field and no doubt
splendid languages such as Haskell rightfully glory in that distinction.
However, Python is first and foremost a *pragmatic* language.  You can
use it perfectly well for teaching CS, sure.  But the focus on Python is
on *getting the job done right*.

There are umpteen good reasons why EAFP is vastly superior to LBYL.  For
example, we can just focus on the fact that these days we work mostly on
multiprogrammed machines.  While script A is running, some other programs
B, C, D, ... are typically also running -- and they might be mucking
with the same directories and/or files that A is working with.

So, if A's structure is:

    if iswhatiwant(thefile):
        useappropriately(thefile)
    else:
        dealwithwrongness()

then A is buggy.  That is because, between the moment in which the test
'iswhatiwant' runs (and returns a true value), and the later moment in
which procedure 'useappropriately' runs, *just about anything may have
happened* -- in particular, some other program Z might have removed or
modified 'thefile' so that it's NOT what A wants any more.  I.e., A may
lose control of the CPU between the moment it tests and the later time
in which it uses the result of that test.

This is known as a "race condition" and it's among the hardest problems
you may run into.  A may seem to be running just fine 99 times and then
the 100th time BOOM -- because of accidents of timing between A and
other stuff that may be running "at the same time"... a "race", so to
speak, whence the name whereby this horrid condition is known.

Fortunately, in a language with good support for exceptions such as
Python, you are NOT doomed to enter the hell of race conditions -- just
use EAFP instead of LBYL:

    try:
        useappropriately(thefile)
    except ItWasWrong, howwasitwrong:
        dealwithwrongness()

See how deeply simpler this is?  'useappropriately' just ASSUMES the
file is 'what A wants' and raises an ItWasWrong exception if the
assumption proves to be unfounded.  You don't have to code a
separate 'iswhatiwant' test -- what you DO want is determined inherently
by what 'useappropriately' tries to do.  No race conditions, no code
that must duplicate the set of conditions to be checked for, no
duplicate work at runtime in terms of system calls to determine
if a condition holds followed by system calls to take advantaqe
of that condition.

This risks leaving the impression that EAFP is a panacea - it isn't,
and it has its own issues to watch for -- it's simply heads and
shoulders above LBYL in most practical cases.  Please see my more
detailed discussions of this in the Cookbook and the Nutshell for
something more about error-checking strategies.


Alex




More information about the Python-list mailing list