EAFP gone wrong
Arnaud Delobelle
arnodel at googlemail.com
Tue Feb 9 23:52:35 CET 2010
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.
--
Arnaud
More information about the Python-list
mailing list