首页 > 解决方案 > Python AST:类型错误重写节点

问题描述

我正在尝试使用 PLY 和 Python 的 AST 从头开始​​创建方程求解器。

2 + x从我首先翻译成的输入开始N.Number(2) + x。为什么?因为我正在使用我自己的实数类。

现在,我正在从第一步的输出创建一个 AST。在这里,我想重写“x”,通过函数调用节点更改其名称节点以获得如下内容:N.Number(2) + N.Number(42).

但我得到这个 TypeError :

Traceback (most recent call last):
  File "test_ast.py", line 52, in <module>
    print(eval(compile(yop, filename="", mode="eval")))
TypeError: required field "value" missing from Attribute

到目前为止,这是我的代码:

class RewriteName(ast.NodeTransformer):
    def visit_Name(self, node):
        if node.id == 'x':
            return ast.copy_location(ast.Call(func=ast.Attribute(value=ast.Name(id='N', ctx=ast.Load()), attr='Number', ctx=ast.Load()),
                args=[ast.Num(n=42)],
                keywords=[]
            ), node)

question = "N.Number(2) + x"
yop = ast.parse(question, mode="eval")

print(ast.dump(yop))
RewriteName().visit(yop)
print(ast.dump(yop))

print(eval(compile(yop, filename="", mode="eval")))

问题显然来自 Rewrite_Name 类。注意它周围的两个打印:这些是它们的输出:

Expression(body=BinOp(left=Call(func=Attribute(value=Name(id='N', ctx=Load()), attr='Number', ctx=Load()), args=[Num(n=2)], keywords=[]), op=Add(), right=Name(id='x', ctx=Load())))

Expression(body=BinOp(left=Call(func=Attribute(attr='Number', ctx=Load()), args=[Num(n=2)], keywords=[]), op=Add(), right=Call(func=Attribute(value=Name(id='N', ctx=Load()), attr='Number', ctx=Load()), args=[Num(n=42)], keywords=[])))

我对 Rewrite_Name 类的 cal 错误地更改了表达式 BinOp 左侧的某些内容,但我不知道为什么。

有人能帮我吗 ?

标签: pythonparsingabstract-syntax-tree

解决方案


我认为您收到此错误是因为当您访问第一个 Name 时,它​​的 id 不是 x。在此代码中,您的函数visit_Name返回None.

添加一个else: return node

class RewriteName(ast.NodeTransformer):
    def visit_Name(self, node):
        if node.id == 'x':
            return ast.copy_location(ast.Call(func=ast.Attribute(value=ast.Name(id='N', ctx=ast.Load()), attr='Number', ctx=ast.Load()),
                args=[ast.Num(n=42)],
                keywords=[]
            ), node)
        else:
            return node

将帮助您避免required field "value" missing from Attribute...

只是为了得到另一个TypeError: required field "lineno" missing from expr;-)


推荐阅读