Розбір і зміна структури коду, безумовно, можливий за допомогою ast
модуля, і я покажу його на прикладі за мить. Однак повернення зміненого вихідного коду неможливе лише з ast
модулем. Для цієї роботи доступні інші модулі, такі як один тут .
ПРИМІТКА: Приклад нижче може розглядатися як вступний підручник щодо використання ast
модуля, але більш повне керівництво по використанню ast
модуля доступне тут у навчальному посібнику щодо змій Green Tree та офіційній документації на ast
модуль .
Вступ до ast
:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> exec(compile(tree, filename="<ast>", mode="exec"))
Hello Python!!
Ви можете проаналізувати код python (представлений у рядку), просто зателефонувавши в API ast.parse()
. Це повертає ручку до структури абстрактного синтаксичного дерева (AST). Цікаво, що ви можете скласти назад цю структуру та виконати її, як показано вище.
Ще один дуже корисний API - це те, ast.dump()
що скидає весь AST у рядковій формі. Він може бути використаний для огляду структури дерева і дуже корисний при налагодженні. Наприклад,
На 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)])"
На 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=[]))])"
Зауважте різницю синтаксису для оператора друку в Python 2.7 проти Python 3.5 та різниці в типі AST-вузла у відповідних деревах.
Як змінити код за допомогою ast
:
Тепер давайте подивимось на приклад модифікації коду python за ast
модулем. Основним інструментом модифікації структури AST є ast.NodeTransformer
клас. Всякий раз, коли потрібно змінювати AST, йому / їй потрібно підкласити його і відповідно записати Трансформацію (-ів) вузла.
Для нашого прикладу спробуємо написати просту утиліту, яка перетворює Python 2, друкує заяви на виклики функції Python 3.
Роздрукувати заяву до утиліти для перетворення викликів 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])
Цю утиліту можна спробувати на невеликому прикладі, наприклад, наведеному нижче, і він повинен працювати добре.
Тестовий вхідний файл: 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()
Зверніть увагу, що перетворення вище є лише ast
підручником, а в реальному випадку потрібно переглянути всі різні сценарії, такі як print " x is %s" % ("Hello Python")
.