[Python] AST(抽象構文木)からコードを生成する
python の標準ライブラリから取得できるAST(抽象構文木)からpython のコードを生成してみます。
環境
python3.7.2
ASTとは
Abstract Syntax Treeの略で、日本語にすると抽象構文木です。
astor
https://github.com/berkerpeksag/astor
今回、ASTからコードを生成するのに利用するのはastorというライブラリです。
pipでインストールすることができます。
pip install astor
今回利用するバージョンは、astor==0.8.1
です。
ASTを得る
ASTを得るには標準モジュールのastを利用します。
import ast
input_source = """
def hoge(a,b=1):
return a+b
a = 1
print(hoge(a))
"""
ast_object = ast.parse(input_source)
ast.parse
関数で文字列で与えたPythonコードのASTが得られます。
ast.dump
関数を利用すると、どのようなASTに変換されたか、若干見やすくなります。
print(ast.dump(ast.object))
Module(
body=[
FunctionDef(
name='hoge',
args=arguments(
args=[
arg(arg='a', annotation=None),
arg(arg='b', annotation=None)
],
vararg=None,
kwonlyargs=[],
kw_defaults=[],
kwarg=None,
defaults=[Num(n=1)]
),
body=[Return(
value=BinOp(
left=Name(id='a', ctx=Load()),
op=Add(),
right=Name(id='b', ctx=Load())
)
)],
decorator_list=[],
returns=None
),
Assign(
targets=[Name(id='a', ctx=Store())],
value=Num(n=1)
),
Expr(
value=Call(
func=Name(id='print', ctx=Load()),
args=[
Call(
func=Name(id='hoge', ctx=Load()),
args=[Name(id='a', ctx=Load())],
keywords=[]
)
],
keywords=[]
)
)
]
)
※実際には一行で表示されます。見やすくするため整形しています。
ASTからコードを生成する
先ほど得た、ASTからコードを生成してみます。
import astor
source = astor.to_source(ast_object)
print(source)
def hoge(a, b=1):
return a + b
a = 1
print(hoge(a))
astor.to_source
関数にASTを渡すことで、見事Pythonコードになりました。
例として簡単なコードしか挙げていませんが、クラスを利用したコードでも問題なく生成できました。
ASTを直接いじることで、いろいろと楽しいことができそうです。
さいごに
今回は、ASTからコードを生成する方法をメインに紹介したので、ASTからコードを生成するメリットを感じ無かったかも知れませんが、ASTに直接手を加えることでただの文字列置換より高度なコードの置き換えが出来たりするメリットがあったりします。 他の言語からの変換の際に便利だったりします。
より詳しく知りたい場合は、公式ドキュメントを参照してみてください。
https://astor.readthedocs.io/
以上、PythonのASTからPythonのコードを得る方法の紹介でした。
2020/12/6追記 @rhoboro様より教えていただきました。
Python3.9.0 からは ast.unparse
関数が追加されastor
ライブラリを用いなくてもASTからソースコードの文字列を得ることが出来るようになりました。
https://docs.python.org/ja/3/library/ast.html#ast.unparse