2

我在一个文件中有一些数学函数(表示为字符串):

1+a**(b/(3*a+1))
(1+a)**(b/(3*a+1))
...

如何将**字符串中的所有 s转换为 s math.pow

编辑:我要解决的是以下问题:我有很多这样的功能要评估,我不能花太多时间在一个上。

有时函数看起来像这样:

(3**100**100**2)

Python 尝试评估它,这很长。我想有一个错误,而不是:

>>> math.pow(3, math.pow(100, 100))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: math range error

编辑2:谢谢大家的回答,我终于找到了怎么做,你的回答和评论对我帮助很大。我只需要在文件顶部用下一行强制浮点除法:

      from __future__ import division
4

2 回答 2

3

您可以使用以下变压器:

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

在您的特定示例中,您可以使用

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)
于 2013-07-22T14:57:51.037 回答
0

您似乎在这里试图避免的是长整数算术,它可能需要任意大量的时间来执行。解决此问题的最简单方法是:

class Floatify(ast.NodeTransformer):
    def visit_Num(self, node):
        return ast.Num(float(node.n))

使用时:

>>> 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')
于 2013-07-22T15:09:50.160 回答