Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

replace variable names with actual values in an expression in AST python

I have an expression described in variable forms like this

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

I have given values of s1 and s2 that can change according to the need

I can use python ast module to evaluate this expression by replacing the respective s1 and s2 values (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 the need to replace the variables with their actual values.

Thanks

like image 242
Anurag Sharma Avatar asked Oct 16 '14 07:10

Anurag Sharma


People also ask

What is AST function in Python?

The ast module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each Python release; this module helps to find out programmatically what the current grammar looks like. An abstract syntax tree can be generated by passing ast.

What does AST parse do?

In Python, the ast. parse() function splits the source code into tokens based on the grammar. These tokens are then transformed to build an Abstract Syntax Tree (AST). It is a tree representation of a source code.

What is code AST?

An Abstract Syntax Tree, or AST, is a tree representation of the source code of a computer program that conveys the structure of the source code. Each node in the tree represents a construct occurring in the source code.


2 Answers

To evaluate expressions you can use a 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 then as

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

This is roughly how ast.literal_eval is implemented, with the added feature of allowing you to pass values in and without the evaluation of non-numeric expressions.

Nice trick with this operators dictionary, by the way. I'll copy that one :)

like image 95
filmor Avatar answered Oct 03 '22 18:10

filmor


You can use eval function . But you must be careful about using eval because it execute any string, can be very dangerous if you accept strings to evaluate from untrusted input. for example Suppose the string being evaluated is "os.system('rm -rf /')" ? It will really start deleting all the files on your computer.

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

As a better solution you can parse your equation with python's 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 the equation , As a more safer than using input you can use compile and eval !

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

Also you can use sympy that is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries.

like image 40
Mazdak Avatar answered Oct 03 '22 17:10

Mazdak