Python AST:如何获取节点的子节点
我正在使用 Python 2.6.5。
给定一个抽象语法树(Abstract Syntax Tree),我想获取它的子节点。
大多数 StackOverflow 上的帖子讨论的是 ast.NodeVisitor
以及里面定义的方法:visit()
和 generic_visit()
。但是,visit()
和 generic_visit()
并不会直接返回子节点,而是会对它们递归地应用函数。
有没有人能写一段简短的代码来演示一下?Python 库中有没有现成的函数可以做到这一点?
2 个回答
3
ast
模块提供了一个叫做iter_child_nodes
的函数,这个函数可能对你很有帮助。
def iter_child_nodes(node):
"""
Yield all direct child nodes of *node*, that is, all fields that are nodes
and all items of fields that are lists of nodes.
"""
for name, field in iter_fields(node):
if isinstance(field, AST):
yield field
elif isinstance(field, list):
for item in field:
if isinstance(item, AST):
yield item
`
6
节点的子节点属性取决于该节点代表的语法类型。每个节点类都有一个特别的 _fields
属性,这个属性列出了该类拥有的子节点的属性名称。例如,
>>> ast.parse('5+a')
<_ast.Module object at 0x02C1F730>
>>> ast.parse('5+a').body
[<_ast.Expr object at 0x02C1FF50>]
>>> ast.parse('5+a').body[0]
<_ast.Expr object at 0x02C1FBF0>
>>> ast.parse('5+a').body[0]._fields
('value',)
>>> ast.parse('5+a').body[0].value
<_ast.BinOp object at 0x02C1FF90>
>>> ast.parse('5+a').body[0].value._fields
('left', 'op', 'right')
>>> ast.parse('5+a').body[0].value.left
<_ast.Num object at 0x02C1FB70>
等等。
编辑,澄清一下情况
在继续之前,先看看 CPython 抽象语法
考虑一下:
>>> type(ast.parse('5+a'))
<class '_ast.Module'>
实际上,如果你查看语法,第一条生成规则是针对模块的。它似乎接受一系列语句,作为一个叫做 body 的参数。
>>> ast.parse('5+a')._fields
('body',)
>>> ast.parse('5+a').body
[<_ast.Expr object at 0x02E965B0>]
AST 的 _fields
属性就是“body”,而 body 属性是一系列 AST 节点。回到语法,查看 stmt
的生成规则,我们看到 Expr
接受一个名为 value
的单一表达式。
>>> ast.parse('5+a').body[0].value
<_ast.BinOp object at 0x02E96330>
如果我们查找 BinOp 的定义,会发现它接受三个不同的参数,分别是 left、op 和 right。希望你能从这里继续理解下去。