我正在使用Python 2.6.5版本。给定一个抽象语法树,我想获取它的子节点。大多数StackOverflow帖子讨论了ast.NodeVisitor及其定义的方法:visit()、generic_visit()。然而,visit()和generic_visit()并不提供子节点,相反,它们直接递归地应用该函数。请问是否有人能写一段简短的代码来演示一下?Python库中是否存在同样的预定义函数?
包含节点子元素的属性取决于节点所表示的语法类型。每个节点类也有一个特殊的_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>]
_fields
属性只是"body",而body属性是AST节点的序列。回到语法规则,在stmt
的产生规则中,我们可以看到Expr
接受一个名为value
的单个表达式。>>> ast.parse('5+a').body[0].value
<_ast.BinOp object at 0x02E96330>
如果我们查找BinOp的定义,我们会发现它需要三个不同的参数:left、op和right。我希望你能从中得出相关结论。
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
`