Replace variable names with actual values ​​in expression in AST python

I have an expression described in variable forms like

's1*3 - (s2-s1)*1'

      

I have given the values ​​for s1 and s2 which can change as per need

I can use the python ast module to evaluate this expression by replacing the corresponding values ​​of s1 and s2 (s1 = 20, s2 = 30)

import ast
import operator as op

operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,
             ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor,
             ast.USub: op.neg}

def eval_(node):
    if isinstance(node, ast.Num): # <number>
        return node.n
    elif isinstance(node, ast.BinOp): # <left> <operator> <right>
        return operators[type(node.op)](eval_(node.left), eval_(node.right))
    elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
        return operators[type(node.op)](eval_(node.operand))
    else:
    raise TypeError(node)

>>> str1 = '20*3 - (30-20)*1'
>>> node = ast.parse(str1, mode='eval')
>>> eval_(node.body)
50

      

How should I evaluate this expression without having to replace the variables with their actual values.

thank

+3


source to share


3 answers


You can use the function eval

. But you have to be careful with use eval

, because it evaluates any string, it can be very dangerous if you accept strings for evaluation from untrusted input. eg Suppose the string being evaluated is "os.system('rm -rf /')"

? It will actually start deleting all files on your computer.

>>> eval('20*3 - (30-20)*1')
50 

      

As a better solution, you can parse your equation with the python internal compiler :

>>> s1=20
>>> s2=30
>>> eq='s1*3 - (s2-s1)*1'
>>> compiler.parse( eq )
Module(None, Stmt([Discard(Sub((Mul((Name('s1'), Const(3))), Mul((Sub((Name('s2'), Name('s1'))), Const(1))))))]))

      



So, if you want to evaluate an equation as safer than using it input

, you can use compile

eval too!

>>> eq='s1*3 - (s2-s1)*1'
>>> a=compile(eq,'','eval')
>>> eval(a)
50

      

Also you can use which is a Python library for symbolic math. It aims to become a fully functional Computer Algebra System (CAS) while keeping the code as simple as possible to be understandable and easily extensible. SymPy is completely written in Python and does not require any external libraries. sympy

+2


source


To evaluate expressions, you can use NodeVisitor

:

from ast import NodeVisitor

class EvalVisitor(NodeVisitor):
    def __init__(self, **kwargs):
        self._namespace = kwargs

    def visit_Name(self, node):
        return self._namespace[node.id]

    def visit_Num(self, node):
        return node.n

    def visit_NameConstant(self, node):
        return node.value

    def visit_UnaryOp(self, node):
        val = self.visit(node.operand)
        return operators[type(node.op)](val)

    def visit_BinOp(self, node):
        lhs = self.visit(node.left)
        rhs = self.visit(node.right)
        return operators[type(node.op)](lhs, rhs)

    def generic_visit(self, node):
        raise ValueError("malformed node or string: " + repr(node))

      

You can use this evaluator and then



v = EvalVisitor(s1=20, s2=30)
print(v.visit(node.body))

      

This is roughly how it is implemented ast.literal_eval

, with the added function to allow values ​​to be passed to and without evaluating non-numeric expressions.

Nice trick with this dictionary operators

by the way. I'll copy this :)

+3


source


A bit late to the party, but for those interested: It is also possible to achieve this with a slight modification to the OP's code (which looks surprisingly similar to this , by the way ). Here he is:

In the function definition, eval_

add another one elif

like this:

...
elif isinstance(node, ast.Name):
    return operators[node.id]
...

      

Then you can just add your variables to the operators

dict. Using the OP's example:

>>> s1=20
>>> s2=30
>>> operators['s1']=s1
>>> operators['s2']=s2
>>> node = ast.parse('s1*3 - (s2-s1)*1', mode='eval')
>>> eval_(node.body)
50

      

The props should go to this module based answerasteval

. Also see the asteval

source
.

0


source







All Articles