LBYL vs EAFP

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Feb 4 23:52:18 EST 2013


On Mon, 04 Feb 2013 16:46:11 -0700, Ian Kelly wrote:

> Presumably if the operation requires
> a number, then it will at some point perform some kind of numerical
> manipulation that will raise a TypeError if one is not passed. If the
> operation succeeds, then the object supported all the operations you
> asked of it, so in what sense would the program be doing the wrong
> thing?

It might not support *all* the operations. Consider a toy function like 
this:

def toy(x):  # Don't try this at home!
    return x*10000000000 + 1

If you pass a non-empty list, Python will:

- try to allocate a chunk of memory of at least 4 GB (estimated), which 
may cause quite a bit of thrashing;

- if somehow this succeeds, then it will create a list and populate it 
with rather a lot of duplicated references;

- at which point it will then try to add a list to an int, and raise an 
exception;

- and then deallocate a huge list, causing more thrashing.


So there are consequences to allowing exceptions to occur in arbitrary 
places.

There's also the principle that it is best to raise an exception as early 
as possible. It's easier to track down errors at the point they are 
introduced than long afterwards.

And finally, even worse than exceptions are silent failures of semantics: 
code that does the wrong thing rather than fail loudly and safely. Just 
because the code doesn't fail, doesn't mean it has worked, and an 
exception is much better than a silent failure. You seem to be making the 
classic mistake of thinking that exceptions are something to avoid:

"I find it amusing when novice programmers believe their main job is 
preventing programs from crashing. [...] More experienced programmers 
realize that correct code is great, code that crashes could use 
improvement, but incorrect code that doesn’t crash is a horrible 
nightmare."  -- Chris Smith

http://cdsmith.wordpress.com/2011/01/09/an-old-article-i-wrote/


Duck-typing is not a panacea, and it too has failure modes. The usual 
example is, suppose you have a graphics application that expects an 
object with a "draw" method:

pencil.draw()
paintbrush.draw()
crayon.draw()
six_shooter.draw()  # bang, you've just shot yourself in the foot


So I lean very strongly to some sort of explicit check ahead of time. I'm 
just not sure *what sort* of explicit check.


-- 
Steven



More information about the Python-list mailing list