use*_*978 4 python abstract-syntax-tree
我很感激能学到一些有用的东西,至于现在,我一直在盲目行动。所以问题出在python的ast.NodeTransformer. 我想知道是否可以使用这种方式向现有类添加一个函数,而不是生气。
这就是我到目前为止的处理方式。
import ast, inspect, cla # cla is a name of class to which we want to add a new function
klass = inspect.getsource(cla)
tree = ast.parse(klass)
st = '''def function(): return 1'''
Foo = ast.parse(st)
class AddFunc(ast.NodeTransformer):
def visit_ClassDef(self, node):
return node, node.body + Foo.body
self.generic_visit(node)
inst = AddFunc()
stuff = i.visit(tree)
# now the trouble begins, a compiling..
co = compile(stuff, filename='<ast>', mode='exec')
# i get TypeError: required "lineno" missing from stmt
Run Code Online (Sandbox Code Playgroud)
我已经尝试过(如您可能猜到的那样不成功)通过使用 ast 库辅助函数ast.fix_missing_locations(), 和来处理这个问题ast.copy_locaction(),但在大多数情况下,我最终会猜测或面对类AttributeError内部的元组AddFunc。有人知道如何管理吗?
我在推特上找到了答案:\n https://twitter.com/mitsuhiko/status/91169383254200320 \nmitsuhiko: "TypeError: stmt 中缺少必填字段“lineno”" \xe2\x80\x94 不,你真正的意思是“元组不是一个语句\'。#helpfulpython
\n\n你在这里返回 tuple,但你必须返回 ast
\n\nclass AddFunc(ast.NodeTransformer):\n def visit_ClassDef(self, node):\n node.body += Foo.body\n return node\nRun Code Online (Sandbox Code Playgroud)\n
kolko 的回答是正确的,在这种情况下,您需要返回一个 AST 节点。Foo在这种情况下是一个模块,它的主体应该是构造函数的语句,可以简单地拼接到类定义中。
它有助于理解这ast.NodeTransformer是非常特殊的:
visit通过特定的类名调用方法,忽略层次结构isinstance(AST)and评估返回值isinstance(list),其他任何内容都将被忽略!即使您正在使用ast.fix_missing_locations添加位置数据,您也可能会收到此错误或密切相关的“expr 中缺少 lineno” 。
如果发生这种情况,那是因为你的 AST 有一个在那个地方不允许的元素。使用astunparse.dump重新审视结构。在一个模块体内,只能有语句。在函数 def 中,只能有语句。然后有一些特定的地方可以表达。
要解决这个问题,请写出您希望生成的 python,解析它,转储它并根据您生成的内容检查它。