如何使用 ast.NodeVisitor 的简单示例? [英] Simple example of how to use ast.NodeVisitor?

查看:23
本文介绍了如何使用 ast.NodeVisitor 的简单示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有人有一个简单的例子,在 Python 2.6 中使用 ast.NodeVisitor 来遍历抽象语法树?我不清楚访问和 generic_visit 之间的区别,我找不到任何使用谷歌代码搜索或普通谷歌的例子.

解决方案

ast.visit -- 当然,除非你在子类中覆盖它 -- 当调用访问 ast 时类foo的.Node,如果该方法存在则调用self.visit_foo,否则调用self.generic_visit.后者,同样在 ast 类本身的实现中,只是在每个子节点上调用 self.visit(并且不执行其他操作).

因此,请考虑,例如:

<预><代码>>>>类 v(ast.NodeVisitor):... def generic_visit(self, node):...打印类型(节点).__名称__... ast.NodeVisitor.generic_visit(self, node)...

在这里,我们覆盖了 generic_visit 以打印类名,但调用基类(这样所有子类也将被访问).例如……:

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

发射:

模块八月分配下标姓名加载指数姓名加载店铺添加下标姓名加载指数元组姓名加载姓名加载加载加载

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

<预><代码>>>>w(v) 类:... def visit_Load(self, node): 通过...

现在,当我们访问 Load 节点时,visit 不再分派给 generic_visit,而是分派给我们新的 visit_Load... 根本没有做任何事情.所以:

<预><代码>>>>y = w()>>>y.visit(t)模块八月分配下标姓名指数姓名店铺添加下标姓名指数元组姓名姓名

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

<预><代码>>>>z(v) 类:... def visit_Name(self, node): 打印 'Name:', node.id...>>>z().visit(t)模块八月分配下标姓名:d指数姓名:x店铺添加下标名称: v指数元组姓名:y姓名:x加载加载

但是,NodeVisitor 是一个类,因为它可以在访问期间存储信息.假设我们想要的只是模块"中的一组名称.然后我们不再需要覆盖 generic_visit,而是......:

<预><代码>>>>类所有名称(ast.NodeVisitor):... def visit_Module(self, node):... self.names = set()... self.generic_visit(节点)...打印排序(self.names)... def visit_Name(self, node):... self.names.add(node.id)...>>>所有名称().访问(t)['d', 'v', 'x', 'y']

与需要覆盖 generic_visit 的那些相比,这种事情是一个更典型的用例——通常,您只对几种类型的节点感兴趣,就像我们在这里的 Module 和 Name,所以我们可以覆盖 visit_Modulevisit_Name 并让 ast 的 visit 代表我们进行调度.

Does anyone have a simple example using ast.NodeVisitor to walk the abstract syntax tree in Python 2.6? The difference between visit and generic_visit is unclear to me, and I cannot find any example using google codesearch or plain google.

解决方案

ast.visit -- unless you override it in a subclass, of course -- when called to visit an ast.Node of class foo, calls self.visit_foo if that method exists, otherwise self.generic_visit. The latter, again in its implementation in class ast itself, just calls self.visit on every child node (and performs no other action).

So, consider, for example:

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

Here, we're overriding generic_visit to print the class name, but also calling up to the base class (so that all children will also be visited). So for example...:

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

emits:

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

But suppose we didn't care for Load nodes (and children thereof -- if they had any;-). Then a simple way to deal with that might be, e.g.:

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

Now when we're visiting a Load node, visit dispatches, NOT to generic_visit any more, but to our new visit_Load... which doesn't do anything at all. So:

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

or, suppose we also wanted to see the actual names for Name nodes; then...:

>>> 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

But, NodeVisitor is a class because this lets it store information during a visit. Suppose all we want is the set of names in a "module". Then we don't need to override generic_visit any more, but rather...:

>>> 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']

This kind of thing is a more typical use case than ones requiring overrides of generic_visit -- normally, you're only interested in a few kinds of nodes, like we are here in Module and Name, so we can just override visit_Module and visit_Name and let ast's visit do the dispatching on our behalf.

这篇关于如何使用 ast.NodeVisitor 的简单示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆