Sin duda, es posible analizar y modificar la estructura del código con la ayuda del ast
módulo y lo mostraré en un ejemplo en un momento. Sin embargo, no es posible volver a escribir el código fuente modificado ast
solo con el módulo. Hay otros módulos disponibles para este trabajo, como uno aquí .
NOTA: El ejemplo a continuación puede tratarse como un tutorial introductorio sobre el uso del ast
módulo, pero una guía más completa sobre el uso del ast
módulo está disponible aquí en el tutorial sobre serpientes de Green Tree y la documentación oficial sobre el ast
módulo .
Introducción a ast
:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> exec(compile(tree, filename="<ast>", mode="exec"))
Hello Python!!
Puede analizar el código de Python (representado en una cadena) simplemente llamando a la API ast.parse()
. Esto devuelve el identificador a la estructura del Árbol de sintaxis abstracta (AST). Curiosamente, puede volver a compilar esta estructura y ejecutarla como se muestra arriba.
Otra API muy útil es la ast.dump()
que descarga todo el AST en forma de cadena. Se puede usar para inspeccionar la estructura de árbol y es muy útil en la depuración. Por ejemplo,
En Python 2.7:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> ast.dump(tree)
"Module(body=[Print(dest=None, values=[Str(s='Hello Python!!')], nl=True)])"
En Python 3.5:
>>> import ast
>>> tree = ast.parse("print ('Hello Python!!')")
>>> ast.dump(tree)
"Module(body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Str(s='Hello Python!!')], keywords=[]))])"
Observe la diferencia en la sintaxis para la declaración de impresión en Python 2.7 frente a Python 3.5 y la diferencia en el tipo de nodo AST en los árboles respectivos.
Cómo modificar el código usando ast
:
Ahora, echemos un vistazo a un ejemplo de modificación del código de Python por ast
módulo. La herramienta principal para modificar la estructura AST es la ast.NodeTransformer
clase. Cada vez que uno necesita modificar el AST, él / ella necesita subclase de él y escribir Transformaciones de Nodo en consecuencia.
Para nuestro ejemplo, intentemos escribir una utilidad simple que transforme las declaraciones de Python 2, print en llamadas a funciones de Python 3.
Declaración de impresión en la utilidad de conversión de llamadas Fun: print2to3.py:
#!/usr/bin/env python
'''
This utility converts the python (2.7) statements to Python 3 alike function calls before running the code.
USAGE:
python print2to3.py <filename>
'''
import ast
import sys
class P2to3(ast.NodeTransformer):
def visit_Print(self, node):
new_node = ast.Expr(value=ast.Call(func=ast.Name(id='print', ctx=ast.Load()),
args=node.values,
keywords=[], starargs=None, kwargs=None))
ast.copy_location(new_node, node)
return new_node
def main(filename=None):
if not filename:
return
with open(filename, 'r') as fp:
data = fp.readlines()
data = ''.join(data)
tree = ast.parse(data)
print "Converting python 2 print statements to Python 3 function calls"
print "-" * 35
P2to3().visit(tree)
ast.fix_missing_locations(tree)
# print ast.dump(tree)
exec(compile(tree, filename="p23", mode="exec"))
if __name__ == '__main__':
if len(sys.argv) <=1:
print ("\nUSAGE:\n\t print2to3.py <filename>")
sys.exit(1)
else:
main(sys.argv[1])
Esta utilidad se puede probar en un pequeño archivo de ejemplo, como el siguiente, y debería funcionar bien.
Archivo de entrada de prueba: py2.py
class A(object):
def __init__(self):
pass
def good():
print "I am good"
main = good
if __name__ == '__main__':
print "I am in main"
main()
Tenga en cuenta que la transformación anterior es solo para ast
fines de tutoría y, en el caso real, el escenario tendrá que observar todos los escenarios diferentes, tales como print " x is %s" % ("Hello Python")
.