ast.NodeVisitorを使用してPython2.6の抽象構文木を歩く簡単な例はありますか?visitとgeneric_visitの違いは私にはわかりません。また、googlecodesearchまたはplaingoogleを使用した例は見つかりません。
3 に答える
ast.visit
--もちろん、サブクラスでオーバーライドしない限り、-- ast.Node
ofクラスにアクセスするために呼び出された場合、そのメソッドが存在する場合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
ただし、ロードノード(およびその子-存在する場合は;-)を気にしなかったとします。次に、これに対処する簡単な方法は次のようになります。
>>> class w(v):
... def visit_Load(self, node): pass
...
これで、Loadノードにアクセスしているときに、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
ことができます。私たちに代わって派遣。
ast.pyのコードを見ると、自分のウォーカーをコピーして貼り付けてロールするのはそれほど難しくありません。例えば
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()
generic_visit
カスタムビジター(つまり、visit_Name)が見つからない場合に呼び出されます。これが私が最近ast.NodeVisitorで書いたコードです:https ://foss.heptapod.net/pypy/pypy/-/blob/80ead76ab428100ffeb01109c7fc0d94f1048af2/py/_code/_assertionnew.pyそれはASTノードを解釈してデバッグ情報を取得しますそれらのいくつかはgeneric_visit
、特別な実装が提供されていない場合にフォールバックします。