Python AST,ast.NodeTransformer,TypeError:stmt缺少必需字段'lineno'。

8
我很想学点有用的东西,因为现在我一直在盲目地摸索。 问题出在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

我尝试过(不成功,你可能已经猜到了)使用ast库的辅助函数ast.fix_missing_locations()和ast.copy_location()来处理这个问题,但在大多数情况下,我最终只能猜测或面对AddFunc类中的元组引发的AttributeError。有人有什么想法,如何解决这个问题吗?
2个回答

9

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

理解ast.NodeTransformer非常重要:

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

即使你使用ast.fix_missing_locations添加位置数据,你也可能会遇到这个错误或者与之紧密相关的"lineno missing from expr"错误。

如果发生这种情况,那么你的AST中有一个不允许出现在那个位置的元素。使用astunparse.dump仔细检查结构。在模块主体中,只能有语句。在函数定义中,只能有语句。然后有特定的地方可以有表达式。

为了解决这个问题,先编写你希望生成的Python代码,然后解析它,转储它并将其与你正在生成的代码进行比较。


6
我在Twitter上找到了答案: https://twitter.com/mitsuhiko/status/91169383254200320 mitsuhiko:“TypeError:语句中缺少必需字段“lineno”” - 不,你实际上想表达的是“元组不是语句”。#helpfulpython
你在这里返回元组,但你必须返回ast。
class AddFunc(ast.NodeTransformer):
  def visit_ClassDef(self, node):
      node.body += Foo.body
      return node

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接