¿Alguien tiene un ejemplo simple usando ast.NodeVisitor para recorrer el árbol de sintaxis abstracta en Python 2.6? La diferencia entre visit y generic_visit no está clara para mí, y no puedo encontrar ningún ejemplo usando google codesearch o plain google.Ejemplo simple de cómo usar ast.NodeVisitor?
Respuesta
ast.visit
- menos que lo sustituya en una subclase, por supuesto - cuando se llama a visitar una clase de ast.Node
foo
, pide self.visit_foo
si existe ese método, de lo contrario self.generic_visit
. Este último, de nuevo en su implementación en la clase ast
, simplemente llama al self.visit
en cada nodo secundario (y no realiza ninguna otra acción).
Por lo tanto, consideramos, por ejemplo:
>>> class v(ast.NodeVisitor):
... def generic_visit(self, node):
... print type(node).__name__
... ast.NodeVisitor.generic_visit(self, node)
...
Aquí, estamos anulando generic_visit
para imprimir el nombre de la clase, pero también llamar a la clase base (por lo que también se visitaron todos los niños) Así, por ejemplo ...:
>>> x = v()
>>> t = ast.parse('d[x] += v[y, x]')
>>> x.visit(t)
emite:
Module
AugAssign
Subscript
Name
Load
Index
Name
Load
Store
Add
Subscript
Name
Load
Index
Tuple
Name
Load
Name
Load
Load
Load
Pero supongamos que no cuidar de los nodos de carga (y los niños de los mismos - si tenían alguna ;-). A continuación, una forma sencilla de hacer frente a ese podría ser, por ejemplo:
>>> class w(v):
... def visit_Load(self, node): pass
...
Ahora, cuando estamos visitando un nodo de carga, visit
despachos, NO a generic_visit
más, pero a nuestro nuevo visit_Load
... lo que doesn' hacer cualquier cosa. Entonces:
>>> y = w()
>>> y.visit(t)
Module
AugAssign
Subscript
Name
Index
Name
Store
Add
Subscript
Name
Index
Tuple
Name
Name
o, supongamos que también quisiéramos ver los nombres reales de los nodos Nombre; entonces ...:
>>> 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
Pero, NodeVisitor es una clase porque esto le permite almacenar información durante una visita. Supongamos que todo lo que queremos es el conjunto de nombres en un "módulo". Entonces no necesitamos para anular generic_visit
más, sino más bien ...:
>>> 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']
Este tipo de cosas es un caso de uso más típico que los que requieren reemplazos de generic_visit
- normalmente, sólo está interesado en algunos tipos de nodos, como estamos aquí en Módulo y Nombre, por lo que podemos simplemente anular visit_Module
y visit_Name
y dejar que ast 0's visit
haga el envío en nuestro nombre.
generic_visit
se llama cuando no se puede encontrar un visitante personalizado (es decir, nombre_de_la_compra). Aquí hay un fragmento de código que escribí recientemente con ast.NodeVisitor: https://github.com/pypy/pypy/blob/master/py/_code/_assertionnew.py. Interpreta los nodos AST para obtener información de depuración sobre algunos de ellos y vuelve a aparecer con generic_visit
cuando no se proporciona una implementación especial.
Mirando el código en ast.py no es tan difícil copiar y pegar su propio andador. P.ej.
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()
- 1. Ejemplo simple de DispatcherHelper
- 2. ¿Hay un ejemplo SIMPLE de Cómo usar buckminster
- 3. Cómo usar jQuery qTip - Ejemplo simple por favor
- 4. WPF - animación simple ejemplo simple
- 5. Un ejemplo simple de usar el stepper en SBCL
- 6. Simple GWT OpenID Ejemplo
- 7. más simple TBB ejemplo
- 8. OSMDroid ejemplo simple requerido
- 9. UINavigationController: ejemplo más simple
- 10. Cola en C++ - ejemplo simple
- 11. Usar hilos en C en Windows. Ejemplo simple?
- 12. ejemplo de cómo usar fastcgi_finish_request()
- 13. MKAnnotación, ejemplo simple
- 14. Algoritmo de alpinismo simple ejemplo
- 15. simple C++ hash_set ejemplo
- 16. v4l2 muy simple ejemplo
- 17. Ejemplo de cómo usar PyLZMA
- 18. Qt: Ejemplo simple para Quazip
- 19. Django - plantilla simple ejemplo etiqueta
- 20. ejemplo simple para Erlang memoization
- 21. más simple Gson.fromJson ejemplo no
- 22. Ejemplo simple con Servlets de Guice
- 23. Ejemplo o documentación JQuery SlickGrid JSON simple
- 24. Ejemplo simple de bfs ... No lo entiendo
- 25. Buscando un ejemplo de seguridad simple muelle
- 26. Uso simple de IEnumerator (por ejemplo)
- 27. Ejemplo simple de reificación en RDF
- 28. Buscando el ejemplo simple de MVVM Light
- 29. Ejemplo simple de http en Objective-C?
- 30. Ejemplo de animación de tween simple
Gracias! - Esto es exactamente lo que estaba buscando. – lacker
@lacker, de nada! –
Genial, me gustaría entender un poco más la diferencia entre compiler.ast y ast ahora ... –