您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何使用ast.NodeVisitor的简单示例?

如何使用ast.NodeVisitor的简单示例?

ast.visit-当然,除非您在子类中覆盖了它- 当被调用以访问ast.Nodeclass的时fooself.visit_foo如果存在该方法,则调用,否则self.generic_visit。后者再次在类ast本身的实现中,仅self.visit在每个子节点上调用(并且不执行其他任何操作)。

因此,请考虑例如:

>>> class v(ast.NodeVisitor):
...   def generic_visit(self, node):
...     print type(node).__name__
...     ast.NodeVisitor.generic_visit(self, node)
...

在这里,我们不仅要generic_visit打印类名,而且 还要 调用基类(以便也可以访问所有子类)。例如:

>>> x = v()
>>> t = ast.parse('d[x] += v[y, x]')
>>> x.visit(t)

发出:

Module
AugAssign
Subscript
Name
Load
Index
Name
Load
Store
Add
Subscript
Name
Load
Index
Tuple
Name
Load
Name
Load
Load
Load

但是,假设我们不在乎Load节点(及其子节点-如果有的话;-)。那么一个简单的处理方法可能是:

>>> class w(v):
...   def visit_Load(self, node): pass
...

现在,当我们访问一个Load节点时,不再visitgeneric_visit其他节点调度,而是向我们的新visit_Load…调度,这根本不执行任何操作。所以:

>>> y = w()
>>> y.visit(t)
Module
AugAssign
Subscript
Name
Index
Name
Store
Add
Subscript
Name
Index
Tuple
Name
Name

或者,假设我们还想查看Name节点的实际名称;然后…:

>>> class z(v):
...   def visit_Name(self, node): print 'Name:', node.id
... 
>>> z().visit(t)
Module
AugAssign
Subscript
Name: d
Index
Name: x
Store
Add
Subscript
Name: v
Index
Tuple
Name: y
Name: x
Load
Load

但是,NodeVisitor是一个类,因为它使它可以在访问期间存储信息。假设我们想要的只是“模块”中的一组名称。然后我们就不需要重写generic_visit了,而是…:

>>> class allnames(ast.NodeVisitor):
...   def visit_Module(self, node):
...     self.names = set()
...     self.generic_visit(node)
...     print sorted(self.names)
...   def visit_Name(self, node):
...     self.names.add(node.id)
... 
>>> allnames().visit(t)
['d', 'v', 'x', 'y']

这种事情是一个比较典型的使用情况不是要求的覆盖那些generic_visit-通常情况下,你只在几个不同的节点有兴趣,像我们这里的模块和名称,所以我们就可以覆盖visit_Modulevisit_Name让AST的visit做代表我们派遣。

Node 2022/1/1 18:34:43 有423人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶