EAFP gone wrong

Matthew Barnett mrabarnett at mrabarnett.plus.com
Wed Feb 10 00:49:25 CET 2010


Arnaud Delobelle wrote:
> Hi all,
> 
> Hi have a set of classes that represent mathematical objects which can
> be represented as a string using a 'latex' method (after Knuth's famous
> typesetting system).  As I want to be able to typeset some builtin types as
> well, I have a generic function, latex(), as follows:
> 
> def latex(val):
>     try:
>         return val.latex()
>     except AttributeError:
>         if isinstance(val, (tuple, list)):
>             return ", ".join(map(latex, val))
>         elif isinstance(val, dict):
>             return ", ".join(
>                 "%s=%s" % (latex(k), latex(v)) 
>                 for k, v in sorted(val.iteritems())
>             )
>         else:
>             return str(val)
> 
> It's EAFP and I have used this for a while with no problem.  Recently I
> added a new class for 'n choose r' objects, as follows:
> 
> class Choose(Expression):
>    def __init__(self, n, r):
>         self.subexprs = n, r
>         self.n = n
>         self.r = r
>     def calc(self, ns=None, calc=calc):
>         return choose(calc(self.n, ns), calc(self.r, ns))
>     def latex(self):
>         return "{%s \\choose %s}" % (latex(self.n), latex(self.k))
> 
> When I create a Choose object and try to get its latex representation,
> this happens:
> 
>>>> c = Choose(5, 3)
>>>> latex(c)
> '<qmm.maths.expressions.Choose object at 0x17c92d0>'
> 
> This puzzled me for a bit: why is it not trying to use the latex()
> method of the Choose object?  I read and reread the definition of the
> latex() method for a while until I found that there was a typo.  Where
> it says:
> 
>     latex(self.k)
> 
> it should say:
> 
>     latex(self.r)
> 
> Thus it triggers an AttributeError, which is exactly the kind of
> exception that I am catching in the latex() function after trying
> val.latex(). (Of course I could have caught this by calling c.latex()
> directly but it's such a short method definition that I couldn't imagine
> missing the typo!).
> 
> This means that EAFP made me hide a typo which would have been obviously
> detected had I LBYLed, i.e. instead of
> 
>     try:
>         return val.latex()
>     except AttributeError:
>         ...
> 
> do
> 
>     if hasattr(val, 'latex'):
>         return val.latex()
>     else:
>         ...
> 
> 
> So was it wrong to say it's EAFP in this case?  Should I have known to
> LBYL from the start?  How do you decide which one to use?  Up to now, I
> thought it was more or less a matter of taste but now this makes me
> think that at least LBYL is better than catching AttributeError.
> 
> Thanks for any guidance.
> 
In addition to the other replies, you should've tested the Choose class. :-)



More information about the Python-list mailing list