55

ast.NodeVisitorを使用してPython2.6の抽象構文木を歩く簡単な例はありますか?visitとgeneric_visitの違いは私にはわかりません。また、googlecodesearchまたはplaingoogleを使用した例は見つかりません。

4

3 に答える 3

91

ast.visit--もちろん、サブクラスでオーバーライドしない限り、-- ast.Nodeofクラスにアクセスするために呼び出された場合、そのメソッドが存在する場合fooは呼び出します。それ以外の場合は呼び出します。後者も、クラス自体での実装において、すべての子ノードを呼び出すだけです(他のアクションは実行しません)。self.visit_fooself.generic_visitastself.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_Modulevisit_Nameてastに実行させるvisitことができます。私たちに代わって派遣。

于 2009-10-04T02:05:23.483 に答える
14

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()
于 2014-10-15T05:17:50.250 に答える
6

generic_visitカスタムビジター(つまり、visit_Name)が見つからない場合に呼び出されます。これが私が最近ast.NodeVisitorで書いたコードです:https ://foss.heptapod.net/pypy/pypy/-/blob/80ead76ab428100ffeb01109c7fc0d94f1048af2/py/_code/_assertionnew.pyそれはASTノードを解釈してデバッグ情報を取得しますそれらのいくつかはgeneric_visit、特別な実装が提供されていない場合にフォールバックします。

于 2009-10-04T01:52:15.023 に答える