Exemple simple de l'utilisation ast.NodeVisitor?
-
19-09-2019 - |
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.
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.