[Tutor] eval use (directly by interpreter vs with in a script)
Albert-Jan Roskam
fomcl at yahoo.com
Tue Nov 4 17:11:13 CET 2014
----- Original Message -----
> From: Steven D'Aprano <steve at pearwood.info>
> To: tutor at python.org
> Cc:
> Sent: Tuesday, November 4, 2014 4:08 AM
> Subject: Re: [Tutor] eval use (directly by interpreter vs with in a script)
>
> 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]
Aaah *slap against forehead*! I did not know this is legal. MUCH nicer indeed
> 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.
Hmm, I get 1900 occurrences of eval() (and 700 of frozenset, just curious) in Python. That's MUCH, I must be something wrong, but I am rushing now!
import os
import sys
import collections
os.chdir(os.path.dirname(sys.executable))
cmds = ["eval(", "frozenset"]
counter = collections.Counter()
for root, dirs, files in os.walk(".", topdown=False):
for name in files:
if name.endswith(".py"):
contents = open(os.path.join(root, name))
for line in contents:
if not line.startswith("#"):
for cmd in cmds:
if cmd in line:
counter[cmd] += 1
print counter
More information about the Tutor
mailing list