如何在Python中获取完整的AST?
我很喜欢_ast模块提供的选项,它真的很强大。请问有没有办法获取它的完整抽象语法树(AST)呢?
举个例子,如果我获取以下代码的AST:
import os
os.listdir(".")
通过使用:
ast = compile(source_string,"<string>","exec",_ast.PyCF_ONLY_AST)
那么这个ast对象的主体会有两个元素,一个是import对象,另一个是expr对象。不过,我想更进一步,想要获取import和listdir的AST,换句话说,我希望_ast能深入到尽可能低的层级。
我觉得这种事情应该是有可能的。问题是怎么做呢?
补充一下:我所说的最低层级,并不是指访问那些“可见”的东西。我还想获取listdir的实现AST,比如stat和其他可能被调用的函数。
2 个回答
py> ast._fields
('body',)
py> ast.body
[<_ast.Import object at 0xb7978e8c>, <_ast.Expr object at 0xb7978f0c>]
py> ast.body[1]
<_ast.Expr object at 0xb7978f0c>
py> ast.body[1]._fields
('value',)
py> ast.body[1].value
<_ast.Call object at 0xb7978f2c>
py> ast.body[1].value._fields
('func', 'args', 'keywords', 'starargs', 'kwargs')
py> ast.body[1].value.args
[<_ast.Str object at 0xb7978fac>]
py> ast.body[1].value.args[0]
<_ast.Str object at 0xb7978fac>
py> ast.body[1].value.args[0]._fields
('s',)
py> ast.body[1].value.args[0].s
'.'
希望这能帮到你。
通过这种方式,你可以获取整个树结构,一直到最底层,但它确实是以树的形式保存的...所以在每一层,你需要明确访问所需的属性才能获取子节点。例如(我把compile
的结果命名为cf
,而不是ast
,因为那样会隐藏标准库的ast模块——我假设你只有2.5版本,而不是2.6,所以你才使用更底层的_ast
模块,对吧?):
>>> cf.body[0].names[0].name
'os'
这段代码告诉你,import语句正在导入名称os
(而且只有这个,因为.body[0]
中的.names
字段的长度是1,这就是import
)。
在Python 2.6的ast
模块中,你还可以得到一些帮助工具,让你更容易地在树中导航(例如,通过Visitor
设计模式)——但无论是2.5(使用_ast
)还是2.6(使用ast
),整个树的表示方式都是完全一样的。
为了方便地访问树中的所有节点,在2.6中,使用模块ast(没有前导下划线),并根据需要子类化ast.NodeVisitor
(或者等效地递归使用ast.iter_child_nodes
和根据需要使用ast.iter_fields
)。当然,如果你因为某种原因被困在2.5中,这些帮助工具也可以在_ast
上用纯Python实现。