Das Parsen und Ändern der Codestruktur ist sicherlich mit Hilfe des ast
Moduls möglich, und ich werde es gleich in einem Beispiel zeigen. Das Zurückschreiben des geänderten Quellcodes ist jedoch nicht nur mit dem ast
Modul möglich . Für diesen Job stehen andere Module zur Verfügung, z. B. eines hier .
HINWEIS: Das folgende Beispiel kann als einführendes Tutorial zur Verwendung des ast
Moduls behandelt werden. Eine umfassendere Anleitung zur Verwendung des ast
Moduls finden Sie hier im Tutorial zu Green Tree Snakes und in der offiziellen Dokumentation zum ast
Modul .
Einführung in ast
:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> exec(compile(tree, filename="<ast>", mode="exec"))
Hello Python!!
Sie können den Python-Code (in Zeichenfolge dargestellt) analysieren, indem Sie einfach die API aufrufen ast.parse()
. Dadurch wird das Handle an die AST-Struktur (Abstract Syntax Tree) zurückgegeben. Interessanterweise können Sie diese Struktur zurückkompilieren und wie oben gezeigt ausführen.
Eine weitere sehr nützliche API ist die, ast.dump()
die den gesamten AST in einer Zeichenfolgenform ausgibt. Es kann zur Überprüfung der Baumstruktur verwendet werden und ist beim Debuggen sehr hilfreich. Beispielsweise,
Auf 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)])"
Auf 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=[]))])"
Beachten Sie den Unterschied in der Syntax für die Druckanweisung in Python 2.7 gegenüber Python 3.5 und den Unterschied im Typ des AST-Knotens in den jeweiligen Bäumen.
So ändern Sie Code mithilfe von ast
:
Schauen wir uns nun ein Beispiel für die Änderung des Python-Codes nach ast
Modulen an. Das Hauptwerkzeug zum Ändern der AST-Struktur ist ast.NodeTransformer
class. Wann immer jemand den AST ändern muss, muss er eine Unterklasse daraus erstellen und die Knotenumwandlung (en) entsprechend schreiben.
In unserem Beispiel versuchen wir, ein einfaches Dienstprogramm zu schreiben, das die Python 2-Druckanweisungen in Python 3-Funktionsaufrufe umwandelt.
Dienstprogramm Print to Fun Call Converter drucken: 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])
Dieses Dienstprogramm kann für kleine Beispieldateien wie die folgende ausprobiert werden und sollte einwandfrei funktionieren.
Testeingabedatei: 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()
Bitte beachten Sie, dass die obige Transformation nur zu ast
Lernzwecken dient und im realen Fall alle verschiedenen Szenarien betrachtet werden müssen, wie z print " x is %s" % ("Hello Python")
.