Przetwarzanie i modyfikowanie struktury kodu jest na pewno możliwe przy pomocy ast
modułu i za chwilę pokażę to na przykładzie. Jednak zapis zmodyfikowanego kodu źródłowego nie jest możliwy w przypadku ast
samego modułu. Istnieją inne moduły dostępne do tego zadania, takie jak jeden tutaj .
UWAGA: Poniższy przykład może być traktowany jako wprowadzenie do korzystania z ast
modułu, ale bardziej obszerny przewodnik na temat korzystania z ast
modułu jest dostępny tutaj w samouczku Green Tree snakes i oficjalnej dokumentacji ast
modułu .
Wprowadzenie do ast
:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> exec(compile(tree, filename="<ast>", mode="exec"))
Hello Python!!
Możesz przeanalizować kod Pythona (przedstawiony w postaci ciągu znaków), po prostu wywołując interfejs API ast.parse()
. To zwraca uchwyt do struktury abstrakcyjnego drzewa składni (AST). Co ciekawe, możesz skompilować tę strukturę i wykonać ją, jak pokazano powyżej.
Innym bardzo przydatnym interfejsem API jest ast.dump()
zrzucanie całego AST w postaci łańcucha. Może być używany do sprawdzania struktury drzewa i jest bardzo pomocny w debugowaniu. Na przykład,
W Pythonie 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)])"
W Pythonie 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=[]))])"
Zwróć uwagę na różnicę w składni instrukcji print w Pythonie 2.7 w porównaniu z Pythonem 3.5 i różnicę w typie węzła AST w odpowiednich drzewach.
Jak zmodyfikować kod za pomocą ast
:
Przyjrzyjmy się teraz przykładowi modyfikacji kodu w Pythonie według ast
modułu. Głównym narzędziem do modyfikowania struktury AST jest ast.NodeTransformer
klasa. Ilekroć trzeba zmodyfikować AST, musi utworzyć podklasę z niej i odpowiednio napisać transformację (e) węzła.
W naszym przykładzie spróbujmy napisać proste narzędzie, które przekształca instrukcje Python 2, print na wywołania funkcji Python 3.
Wydrukuj instrukcję do narzędzia konwertera połączeń 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])
To narzędzie można wypróbować na małym pliku przykładowym, takim jak poniższy, i powinno działać dobrze.
Plik wejściowy testu: 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()
Należy pamiętać, że powyższa transformacja jest tylko w celach ast
samouczkowych iw prawdziwym przypadku trzeba będzie spojrzeć na wszystkie różne scenariusze, takie jak print " x is %s" % ("Hello Python")
.