Python 3.x 如何在python3中使用AST递归简化数学表达式?
我有一个数学表达式:Python 3.x 如何在python3中使用AST递归简化数学表达式?,python-3.x,recursion,abstract-syntax-tree,Python 3.x,Recursion,Abstract Syntax Tree,我有一个数学表达式: tree = ast.parse('1 + 2 + 3 + x') 对应于此抽象语法树: Module(body=[Expr(value=BinOp(left=BinOp(left=BinOp(left=Num(n=1), op=Add(), right=Num(n=2)), op=Add(), right=Num(n=3)), op=Add(), right=Name(id='x', ctx=Load())))]) 我想简化它,也就是说,得到这个: Module(bo
tree = ast.parse('1 + 2 + 3 + x')
对应于此抽象语法树:
Module(body=[Expr(value=BinOp(left=BinOp(left=BinOp(left=Num(n=1), op=Add(), right=Num(n=2)), op=Add(), right=Num(n=3)), op=Add(), right=Name(id='x', ctx=Load())))])
我想简化它,也就是说,得到这个:
Module(body=[Expr(value=BinOp(left=Num(n=6), op=Add(), right=Name(id='x', ctx=Load())))])
根据,我应该使用NodeTransformer类。文件中的建议如下:
请记住,如果正在操作的节点具有子节点,则
必须自己变换子节点或调用
首先对节点使用泛型_visit()方法
我尝试实现我自己的转换器:
class Evaluator(ast.NodeTransformer):
def visit_BinOp(self, node):
print('Evaluating ', ast.dump(node))
for child in ast.iter_child_nodes(node):
self.visit(child)
if type(node.left) == ast.Num and type(node.right) == ast.Num:
print(ast.literal_eval(node))
return ast.copy_location(ast.Subscript(value=ast.literal_eval(node)), node)
else:
return node
在这种特殊情况下,它应该做的是将1+2简化为3,然后将3+3简化为6。
它确实简化了我想要简化的二进制操作,但它不会更新原始语法树。我尝试了不同的方法,但仍然不知道如何递归地简化所有二进制操作(以深度优先的方式)。谁能给我指一下正确的方向吗
谢谢。对于
访问*
方法,有三种可能的返回值:
None
表示节点将被删除节点
(节点本身),这意味着不会应用任何更改因此,当您想用
Num
替换BinOp
时,需要返回一个新的Num
节点。表达式的计算不能通过ast.literal\u eval
完成,因为此函数仅计算文字(而不是任意表达式)。例如,您可以使用eval
因此,您可以使用以下节点转换器类:
导入ast
类计算器(ast.NodeTransformer):
ops={
ast.Add:“+”,
ast.Sub:“-”,
ast.Mult:“*”,
ast.Div:“/”,
#在这里定义更多
}
def visit_BinOp(自身,节点):
self.generic_访问(节点)
如果isinstance(node.left,ast.Num)和isinstance(node.right,ast.Num):
#在Python上,我也尝试用ast.walk解决这个问题,但发现了相同的错误:我执行的更改不会持久。请注意,1+2+3+x
在执行之前已经优化到6+x
。反汇编(dis.dis('1+2+3+x')
)允许看到这一点。“表达式的求值不能通过ast.literal\u eval完成,因为此函数只求值文本(而不是任意表达式)”,但我使用literal\u eval求值表达式(1+1),它返回2。这就是我想要的:在不涉及变量的情况下简化操作。如果您使用的是Python,我不能也使用literal_eval吗?@GuillermoMosse