如何使用ast(抽象语法树)模块获取节点的完整“路径”?

问题描述 投票:0回答:1

我正在修补 Python 的

ast
(抽象语法树)模块。

使用

ast.NodeVisitor
,可以遍历源树并显示信息,例如每个节点的名称,如下所示:

class MyAST(ast.NodeVisitor):      

     def visit_ClassDef(self, node):
         print(node.col_offset * " " +node.name)         
         self.generic_visit(node)   

     def visit_FunctionDef(self, node):         
         print(node.col_offset * " " + node.name)     
         self.generic_visit(node)   

然后可以将其用于任何代码片段,如下所示:

tree = ast.parse(open("/path/to/file.py").read())
MyAST().visit(tree)

这将输出类似的内容(例如,在 requests 包中的 models.py 上使用):

RequestEncodingMixin                                                                                                                                                         
    path_url                                                                                                                                                                 
    _encode_params                                                                                                                                                           
    _encode_files                                                                                                                                                            
RequestHooksMixin                                                                                                                                                            
    register_hook                                                                                                                                                            
    deregister_hook                                                                                                                                                          
Request                                                                                                                                                                      
    __init__
    __repr__
    prepare
(...)

我想知道对于给定的节点,它的完整“路径”。在上面的输出示例中,当我位于

FunctionDef
节点
deregister_hook
时,我想知道它的父节点是
ClassDef
RequestHooksMixin
,以便我可以输出类似
RequestHooksMixin.deregister_hook
的内容。

python abstract-syntax-tree
1个回答
0
投票

ast.NodeVisitor
的设计并未考虑嵌套级别,因此它不是使用基于级别的缩进生成输出的最佳工具。

相反,您可以使用

ast.iter_child_nodes
递归遍历每个节点的直接子节点,并输出该节点并在它是类或函数时增加缩进级别

import ast

def build_tree(node):
    def _visit(node, level=0):
        if isinstance(node, (ast.ClassDef, ast.FunctionDef)):
            yield node.name, level
            level += 1
        for child in ast.iter_child_nodes(node):
            yield from _visit(child, level)
    return '\n'.join(f'{"    " * level}{name}' for name, level in _visit(node))

这样:

source = '''
class Foo:
    def method1(self):
        pass
    def method2(self):
        pass

class Bar:
    def method1(self):
        pass
    def method2(self):
        pass
'''
print(build_tree(ast.parse(source)))

输出:

Foo
    method1
    method2
Bar
    method1
    method2

演示:https://ideone.com/aQHqbi

© www.soinside.com 2019 - 2024. All rights reserved.