[Tutor] eval use (directly by interpreter vs with in a script)
Steven D'Aprano
steve at pearwood.info
Tue Nov 4 04:08:03 CET 2014
On Mon, Nov 03, 2014 at 09:33:18AM -0800, Albert-Jan Roskam wrote:
> >Real question is what you're trying to do. eval() and exec() are to be
> >avoided if possible, so the solutions are not necessarily the easiest.
>
> I sometimes do something like
> ifelse = "'teddybear' if bmi > 30 else 'skinny'"
> weightcats = [eval(ifelse) for bmi in bmis]
>
> Would this also be a *bad* use of eval? It can be avoided, but this is so concise.
Two lines, 92 characters. This is more concise:
weightcats = ['teddybear' if bmi > 30 else 'skinny' for bmi in bmis]
One line, 68 characters. And it will be faster too. On average, you
should expect that:
eval(expression)
is about ten times slower than expression would be on its own.
In my opinion, a *minimum* requirement for eval() is that you don't know
what the code being evaluated will be when you're writing it. If you can
write a fixed string inside the eval, like your example above, or a
simpler case here:
results = [eval("x + 2") for x in values]
then eval is unneccessary and should be avoided, just write the
expression itself:
results = [x + 2 for x in values]
You *may* have a good reason for using eval if you don't know what the
expression will be until runtime:
results = [eval("x %c 2" % random.choice("+-/*")) for x in values]
but even then there is often a better way to get the same result, e.g.
using getattr(myvariable, name) instead of eval("myvariable.%s" % name).
In the case of the random operator, I'd write something like this:
OPERATORS = {'+': operator.add, '-': operator.sub,
'/': operator.truediv, '*': operator.mul}
results = [OPERATORS[random.choice("+-/*")](x, 2) for x in values]
which in this case is a little longer but safer and probably faster.
It's also more easily extensible to a wider range of operators and even
functions.
--
Steven
More information about the Tutor
mailing list