45 lines
1.1 KiB
Python
45 lines
1.1 KiB
Python
|
# Adapted from https://stackoverflow.com/a/9558001/2536294
|
||
|
|
||
|
import ast
|
||
|
import operator as op
|
||
|
|
||
|
# supported operators
|
||
|
operators = {
|
||
|
ast.Add: op.add,
|
||
|
ast.Sub: op.sub,
|
||
|
ast.Mult: op.mul,
|
||
|
ast.Div: op.truediv,
|
||
|
ast.FloorDiv: op.floordiv,
|
||
|
ast.Mod: op.mod,
|
||
|
ast.Pow: op.pow,
|
||
|
ast.USub: op.neg,
|
||
|
}
|
||
|
|
||
|
|
||
|
def eval_expr(expr):
|
||
|
"""
|
||
|
>>> eval_expr('2*6')
|
||
|
12
|
||
|
>>> eval_expr('2**6')
|
||
|
64
|
||
|
>>> eval_expr('1 + 2*3**(4) / (6 + -7)')
|
||
|
-161.0
|
||
|
"""
|
||
|
try:
|
||
|
return eval_(ast.parse(expr, mode="eval").body)
|
||
|
except (TypeError, SyntaxError, KeyError) as e:
|
||
|
raise ValueError(
|
||
|
f"{expr!r} is not a valid or supported arithmetic expression."
|
||
|
) from e
|
||
|
|
||
|
|
||
|
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)
|