Using eval with substitutions

Carl Banks pavlovevidence at gmail.com
Sat Sep 2 06:33:10 CEST 2006


abhishek at ocf.berkeley.edu wrote:
> >>> a,b=3,4
> >>> x="a+b"
> >>> eval(x)
> 7
> >>> y="x+a"
>
> Now I want to evaluate y by substituting for the evaluated value of x.
> eval(y) will try to add "a+b" to 3 and return an error. I could do
> this,
> >>> eval(y.replace("x",str(eval(x))))
> 10
>
> but this becomes unwieldy if I have
> >>> w="y*b"
> and so on, because the replacements have to be done in exactly the
> right order. Is there a better way?

Careful.  Here be dragons.

There are two legitimate uses for eval and exec: A. deliberately giving
the user the power to run arbitrary Python code, and B. evaluating
expressions constructed within the program using only trusted and
carefully verified input.  Make sure your use case is one of these.

Anyways, although what you want to do is even more error prone and
dangerous than simple uses of eval, it can be done.  The thing to do is
to get your list of active symbol definitions into some kind of dict;
for example:

x = "a+b"
y = "x+b"
exprs = { "x": x, "y": y }

Then, if you want to evaluate y, you recursively expand any variables
you find within it. For example:

def expand_sym(sym):
    expr = exprs[sym]
    for subsym in exprs:
        if subsym in expr:
            subexpr = expand_sym(subsym)
            expr = expr.replace(subsym,"(%s)" % subexpr)
    return expr

Then you can eval the expanded expression:

eval(expand_sym("y"))


However, this is just a big potentially dangerous hack.  It's probably
ok for a little calculator you intend only for personal use, but
anything more I highly recommend your script parses the expression and
does symbolic expansion itself, without relying on eval.  That,
however, is quite hard.


Carl Banks




More information about the Python-list mailing list