您通过定义compiler.visitor.ASTVisitor 的子类然后为您希望访问者处理的每种节点类型定义一个方法visitXXX 来创建访问者类(其中XXX 是节点类型的名称 -您链接的文档中的表格中列出了可能的节点类型)。
任何此类方法都将采用一个参数(如果算上self,则为两个),它将是代表访问节点的节点对象。此类对象上可用的属性也列在表中。如果您希望访问者进一步进入树,您应该在节点的每个子节点上调用 visit。
在 compiler.visitor.walk() 方法中,它接受 2 个参数,树和访问者。那些是什么?
tree 是您要处理的 AST,visitor 是您为处理该 AST 而创建的访问者类的一个实例。
我怎样才能获得这些?
您通过在某些 Python 源代码上调用 compiler.parse 来获取 AST,并通过编写访问者类并创建它的实例来获取访问者。
这是一个使用访问者的示例,它简单地计算一段 Python 代码中加法运算符的数量:
import compiler
class PlusCounter(compiler.visitor.ASTVisitor):
def __init__(self):
self.count = 0
def visitAdd(self, node):
self.count += 1
self.visit(node.left)
self.visit(node.right)
plus_counter = PlusCounter()
compiler.walk(compiler.parse("1 + 2 * (3 + 4)"), plus_counter)
print(plus_counter.count)
这是使用未弃用的 ast 包的相同示例,它的工作方式基本相同,但 AST 结构略有不同。与上面的代码不同,这个代码实际上可以在 Python 3 中工作:
import ast
class PlusCounter(ast.NodeVisitor):
def __init__(self):
self.pluses = 0
def visit_Add(self, node):
# We don't need to visit any child nodes here because in the ast package
# the AST is structured slightly differently and Add is merely a child
# node of the BinOp node, which holds the operands. So Add itself has
# no children that need to be visited
self.pluses += 1
plus_counter = PlusCounter()
plus_counter.visit(ast.parse("1 + 2 * (3 + 4)"))
print(plus_counter.pluses)