I need to evaluate a mathematical expression in a string like a * np.exp(b * c)
(with a
, b
and c
being constants or variables available elsewhere in my code).
From this answer to a similar question on SO, I adapted the following code to try with a minimal example (not calling variables but actual numbers as arguments in a first step):
import numpy as np
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_expr(expr):
return eval_(ast.parse(expr, mode='eval').body)
def eval_(node):
if isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
return operators[type(node.op)](eval_(node.left), eval_(node.right))
elif isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.Call):
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name): # for built-in functions like 'max'
print('node.func.id: ', node.func.id)
print('Arguments: ', [eval_(a) for a in node.args])
print('node.func is ast.Name: Now what can I do to actually run the function?')
elif isinstance(node.func, ast.Attribute): # for a call to a module etc
print('node.func.value.id:', node.func.value.id)
print('Arguments: ',[eval_(a) for a in node.args])
print('node.func is ast.Attribute: Now what can I do to actually run the function?')
else:
raise TypeError(node)
print(eval_expr('3*4'))
# 12
eval_expr('max(3, 4)')
# node.func.id: max
# Arguments: [3, 4]
# node.func is ast.Name: Now what can I do to actually run the function?
eval_expr('np.exp(3)')
# node.func.value.id: np
# Arguments: [3]
# node.func is ast.Attribute: Now what can I do to actually run the function?
I tried to identify the different cases for the function calls (i.e., when calling a base function or a function from an external module/library like numpy
), but I don't know how to actually run these functions now.
(In my real case, I think I'd be able to pass actual variables or constants from their names as arguments.)