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

时间:2011-05-15 16:22:42

标签: python abstract-syntax-tree

我正在使用Python 2.6.5。

给定一个抽象语法树,我想获得它的孩子。

我搜索了堆栈溢出但无济于事。大多数帖子都在ast.NodeVisitor上,其中定义的方法为visit,generic_visit()。 但是,AFAIU,visit()generic_visit()不会给孩子们,而是直接在他们身上直接应用这个函数

有人可以写一个简短的代码来证明它吗? python库中是否存在预定义的函数?

谢谢!

2 个答案:

答案 0 :(得分:3)

包含节点子节点的attaributes取决于节点所代表的语法类型。每个节点类还有一个特殊的_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 Abstract Grammar

考虑一下:

>>> type(ast.parse('5+a'))
<class '_ast.Module'>

事实上,如果你看一下语法,第一个生产规则就是模块。它似乎采用一系列陈述,作为一个称为身体的论证。

>>> ast.parse('5+a')._fields
('body',)
>>> ast.parse('5+a').body
[<_ast.Expr object at 0x02E965B0>]

AST的_fields属性只是“body”,body属性是AST节点的序列。回到语法,查看stmt的生产规则,我们看到Expr采用一个名为value

的expr
>>> ast.parse('5+a').body[0].value
<_ast.BinOp object at 0x02E96330>

如果我们查找BinOp的定义,我们会看到它需要3个不同的参数,left,op和right。我希望你能从那里继续前进。

答案 1 :(得分: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                                                 

                                                                               `