math.py 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. """Parse arbitrary math equations in a safe way.
  2. Gratefully copied from https://stackoverflow.com/a/9558001
  3. """
  4. import ast
  5. import operator
  6. from functools import lru_cache
  7. # supported operators
  8. operators = {
  9. ast.Add: operator.add,
  10. ast.Sub: operator.sub,
  11. ast.Mult: operator.mul,
  12. ast.Div: operator.truediv,
  13. ast.Pow: operator.pow,
  14. ast.BitXor: operator.xor,
  15. ast.USub: operator.neg,
  16. }
  17. @lru_cache(maxsize=0)
  18. def compute(expr):
  19. """Parse a mathematical expression and return the answer.
  20. >>> compute('2^6')
  21. 4
  22. >>> compute('2**6')
  23. 64
  24. >>> compute('1 + 2*3**(4^5) / (6 + -7)')
  25. -5.0
  26. """
  27. return _eval(ast.parse(expr, mode='eval').body)
  28. @lru_cache(maxsize=0)
  29. def _eval(node):
  30. if isinstance(node, ast.Num): # <number>
  31. return node.n
  32. elif isinstance(node, ast.BinOp): # <left> <operator> <right>
  33. return operators[type(node.op)](_eval(node.left), _eval(node.right))
  34. elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
  35. return operators[type(node.op)](_eval(node.operand))
  36. else:
  37. raise TypeError(node)