Python AST、ast.NodeTransformer、TypeError:stmt 中缺少必填字段“lineno”

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。有人知道如何管理吗?

kol*_*lko 7

我在推特上找到了答案:\n https://twitter.com/mitsuhiko/status/91169383254200320 \nmitsuhiko: "TypeError: stmt 中缺少必填字段“lineno”" \xe2\x80\x94 不,你真正的意思是“元组不是一个语句\'。#helpfulpython

\n\n

你在这里返回 tuple,但你必须返回 ast

\n\n
class AddFunc(ast.NodeTransformer):\n  def visit_ClassDef(self, node):\n      node.body += Foo.body\n      return node\n
Run Code Online (Sandbox Code Playgroud)\n


Ben*_*Ben 5

kolko 的回答是正确的,在这种情况下,您需要返回一个 AST 节点。Foo在这种情况下是一个模块,它的主体应该是构造函数的语句,可以简单地拼接到类定义中。

它有助于理解这ast.NodeTransformer是非常特殊的:

  • visit通过特定的类名调用方法,忽略层次结构
  • 它使用isinstance(AST)and评估返回值isinstance(list),其他任何内容都将被忽略!

即使您正在使用ast.fix_missing_locations添加位置数据,您也可能会收到此错误或密切相关的“expr 中缺少 lineno” 。

如果发生这种情况,那是因为你的 AST 有一个在那个地方不允许的元素。使用astunparse.dump重新审视结构。在一个模块体内,只能有语句。在函数 def 中,只能有语句。然后有一些特定的地方可以表达。

要解决这个问题,请写出您希望生成的 python,解析它,转储它并根据您生成的内容检查它。