Reputation: 329
I have some mathematical functions (represented as strings) in a file:
1+a**(b/(3*a+1))
(1+a)**(b/(3*a+1))
...
How can I transform all **
s in my string to math.pow
?
Edit: What I'm trying to solve is the following : I've a lot of this functions to evaluate, I can't spend too much time on one.
Sometimes functions look like that :
(3**100**100**2)
Python try to evaluate it, which is very long. I would like to have an error instead like :
>>> math.pow(3, math.pow(100, 100))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: math range error
Edit 2 : Thanx all for answering, I finally found how to do it, and your answers and comments helped me a lot. I just had to force float division with next line at the top of my file :
from __future__ import division
Upvotes: 2
Views: 1409
Reputation: 97601
What you seem to be trying to avoid here is long integer arithmetic, which can take an arbitrarily large amount of time to execute. The easiest way to fix this is:
class Floatify(ast.NodeTransformer):
def visit_Num(self, node):
return ast.Num(float(node.n))
Which when used:
>>> node = ast.parse("(3**100**100**2)", mode="eval")
>>> node = Floatify().visit(node)
>>> code = compile(node, "<string>", mode="eval")
>>> eval(code)
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
eval(code)
File "<string>", line 1, in <module>
OverflowError: (34, 'Result too large')
Upvotes: 0
Reputation: 32222
You can use the following transformer:
import ast
pow_func = ast.parse("math.pow", mode="eval").body
class PowForDoubleStar(ast.NodeTransformer):
def visit_BinOp(self, node):
node.left = self.visit(node.left)
node.right = self.visit(node.right)
if isinstance(node.op, ast.Pow):
node = ast.copy_location(
ast.Call(func=pow_func,
args=[node.left, node.right],
keywords=[]
),
node
)
return node
In your particular example you can execute those code parts using
for line in file:
node = ast.parse(line, mode="eval")
node = PowForDoubleStar().visit(node)
code = compile(node, "<string>", mode="eval")
a, b = 1, 3
result = eval(code)
Upvotes: 3