ast
モジュールの助けを借りて、コード構造を解析および変更することは確かに可能です。それをすぐに例で示します。ただし、変更されたソースコードを書き戻すことは、ast
モジュールだけでは不可能です。このジョブには、ここにあるような他のモジュールが利用可能です。
注:以下の例は、ast
モジュールの使用法の入門チュートリアルとして扱うことができますが、モジュールの使用に関するより包括的なガイドast
は、Green Tree snakesチュートリアルとモジュールの公式ドキュメントでast
入手できます。
はじめにast
:
>>> import ast
>>> tree = ast.parse("print 'Hello Python!!'")
>>> exec(compile(tree, filename="<ast>", mode="exec"))
Hello Python!!
APIを呼び出すだけで、Pythonコード(文字列で表される)を解析できます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のprintステートメントの構文の違いと、それぞれのツリーのASTノードのタイプの違いに注意してください。
を使用してコードを変更する方法ast
:
では、ast
モジュールによるpythonコードの変更の例を見てみましょう。AST構造を変更するための主なツールはast.NodeTransformer
クラスです。ASTを変更する必要があるときはいつでも、ASTをサブクラス化し、それに応じてノード変換を書き込む必要があります。
この例では、Python 2のprintステートメントを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")
。