Python AST:如何获取节点的子节点

6
我正在使用Python 2.6.5版本。给定一个抽象语法树,我想获取它的子节点。大多数StackOverflow帖子讨论了ast.NodeVisitor及其定义的方法:visit()、generic_visit()。然而,visit()和generic_visit()并不提供子节点,相反,它们直接递归地应用该函数。请问是否有人能写一段简短的代码来演示一下?Python库中是否存在同样的预定义函数?
2个回答

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。我希望你能从中得出相关结论。


谢谢您的回复!但是我还没有完全理解它...所以node._fields会给出特定节点的子节点吗?(以元组形式?)...那么body和value表示什么意思呢?感谢您的帮助! - Adwaitvedant

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                                                 

                                                                               `

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