有没有人有一个简单的例子,使用ast.NodeVisitor在Python 2.6中引导抽象语法树?访问和generic_visit之间的区别我不清楚,我找不到任何使用谷歌codesearch或普通谷歌的例子。
答案 0 :(得分:72)
ast.visit
- 除非您在子类中覆盖它,当然 - 当调用以访问ast.Node
类foo
时,如果该方法存在则调用self.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
...
现在,当我们访问加载节点时,visit
不再向generic_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_Module
和visit_Name
,让ast visit
代表我们进行调度。
答案 1 :(得分:12)
查看ast.py中的代码,复制粘贴和滚动自己的助行器并不难。 E.g。
import ast
def str_node(node):
if isinstance(node, ast.AST):
fields = [(name, str_node(val)) for name, val in ast.iter_fields(node) if name not in ('left', 'right')]
rv = '%s(%s' % (node.__class__.__name__, ', '.join('%s=%s' % field for field in fields))
return rv + ')'
else:
return repr(node)
def ast_visit(node, level=0):
print(' ' * level + str_node(node))
for field, value in ast.iter_fields(node):
if isinstance(value, list):
for item in value:
if isinstance(item, ast.AST):
ast_visit(item, level=level+1)
elif isinstance(value, ast.AST):
ast_visit(value, level=level+1)
ast_visit(ast.parse('a + b'))
打印
Module(body=[<_ast.Expr object at 0x02808510>])
Expr(value=BinOp(op=Add()))
BinOp(op=Add())
Name(id='a', ctx=Load())
Load()
Add()
Name(id='b', ctx=Load())
Load()
答案 2 :(得分:5)
generic_visit
。这是我最近用ast.NodeVisitor编写的一段代码:https://bitbucket.org/pypy/pypy/src/6df19fd2b6df6058daf162100cf7ee4521de5259/py/_code/_assertionnew.py?at=default&fileviewer=file-view-default它解释AST节点以获取有关其中一些节点的调试信息,并在未提供特殊实现时使用generic_visit
。