Question

Quelqu'un at-il un exemple simple en utilisant ast.NodeVisitor marcher l'arbre de syntaxe abstraite en Python 2.6? La différence entre la visite et generic_visit est pas clair pour moi, et je ne peux pas trouver un exemple en utilisant google codesearch ou google plaine.

Était-ce utile?

La solution

ast.visit - à moins que vous le remplacer dans une sous-classe, bien sûr - lorsqu'il est appelé à visiter un ast.Node de foo de classe, les appels self.visit_foo si cette méthode existe, sinon self.generic_visit. Ce dernier, encore une fois dans sa mise en œuvre ast de classe elle-même, appelle simplement self.visit sur chaque nœud enfant (et exécute aucune autre action).

Alors, pensez, par exemple:

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

Ici, nous surchargeons generic_visit d'imprimer le nom de classe, mais aussi appelant à la classe de base (de sorte que tous les enfants seront également visités). Ainsi, par exemple ...:

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

émet:

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

Mais supposons que nous ne avons pas essayé nœuds de charge (et les enfants de ceux-ci - si elles avaient tout ;-). Ensuite, un moyen simple de traiter que pourrait être, par exemple:.

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

Maintenant, quand nous la visite d'un noeud de charge, les expéditions de visit, de ne pas generic_visit plus, mais à notre nouvelle visit_Load ... qui ne fait rien du tout. Donc:

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

ou, supposons que nous voulions aussi voir les noms réels pour les noeuds Nom; puis ...:

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

Mais, NodeVisitor est une classe parce que cela laisse stocker des informations lors d'une visite. Supposons tout ce que nous voulons est l'ensemble des noms dans un « module ». Ensuite, on n'a pas besoin de passer outre generic_visit plus, mais ...:

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

Ce genre de chose est un plus cas d'utilisation typique que ceux nécessitant redéfinitions generic_visit - normalement, vous n'êtes intéressé que par quelques types de nœuds, comme nous sommes ici dans le module et le nom, afin que nous puissions simplement passer outre visit_Module et visit_Name et laissez-le visit de ast faire le dispatching en notre nom.

Autres conseils

En regardant le code ast.py ce n'est pas difficile à copier coller et rouler votre propre marcheur. Par exemple.

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

Imprime

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 est appelée lorsque ne peut pas être trouvé un visiteur personnalisé (c.-à-visit_Name). Voici un morceau de code je l'ai écrit récemment avec ast.NodeVisitor: https : //bitbucket.org/pypy/pypy/src/6df19fd2b6df6058daf162100cf7ee4521de5259/py/_code/_assertionnew.py à = default & FileViewer = fichier-view par défaut Il interprète les nœuds AST pour obtenir des informations de débogage sur certains d'entre eux et retombe avec generic_visit quand une mise en œuvre particulière n'est pas fourni.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top