Python で文字列から動的に関数を呼び出す方法について
メソッドやプロパティの動的呼び出しはいくつか解説があったんですが、
グローバル関数や変数の動的呼び出しのやり方がわからなかったので調べました
eval()
eval() を実行すると引数で渡した文字列が Python コードとして評価されます
それを利用して、文字列から任意の関数、変数の値を文字列から呼び出すことができます
公式ドキュメント
http://docs.python.jp/3.5/library/functions.html#eval
こんな感じで使います
def func():
print('func() is called')
global_val = 'this is global'
# 通常のグローバル関数、変数呼び出し
func()
print(global_val)
# 文字列からグローバル関数、変数呼び出し
eval('func')()
print(eval('global_val'))
$ python eval_test.py
func() is called
this is global
func() is called
this is global
これさえあればなんでもできます
globals()
組み込み関数の globals() を呼び出すと、グローバルスコープに定義されている関数、変数のディクショナリを取得できます
公式ドキュメント
http://docs.python.jp/3.5/library/functions.html#globals
こんな感じで使います
def func():
print('func() is called')
# ローカルスコープでの globals()
print(globals())
global_val = 'this is global'
# グローバルスコープでの globals()
print(globals())
# 通常のグローバル関数、変数呼び出し
func()
print(global_val)
# 文字列からグローバル関数、変数呼び出し
globals()['func']()
print(globals()['global_val'])
$ python function_call_test.py
{'global_val': 'this is global', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10b185828>, '__name__': '__main__', '__package__': None, '__doc__': None, '__cached__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, 'func': <function func at 0x10b186950>, '__file__': 'function_call_test.py'}
func() is called
{'global_val': 'this is global', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10b185828>, '__name__': '__main__', '__package__': None, '__doc__': None, '__cached__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, 'func': <function func at 0x10b186950>, '__file__': 'function_call_test.py'}
this is global
func() is called
{'global_val': 'this is global', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10b185828>, '__name__': '__main__', '__package__': None, '__doc__': None, 'func_name': 'func', '__cached__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, 'func': <function func at 0x10b186950>, '__file__': 'function_call_test.py'}
this is global
グローバル関数、グローバル変数共に文字列で呼び出すことができてますね
また、グローバルスコープから呼び出しても、ローカルスコープから呼び出しても globals() の結果は同じことが確認できます
locals()
locals() は globals() と違いローカルスコープに定義されている関数、変数のディクショナリを取得できます
公式ドキュメント
http://docs.python.jp/3.5/library/functions.html#locals
def func():
def local_func():
print('local_func() is called')
print('func() is called')
local_val = 'this is local'
# ローカルスコープでの locals()
print(locals())
# 通常のローカル関数、変数呼び出し
local_func()
print(local_val)
# 文字列からグローバル関数、変数呼び出し
locals()['local_func']()
print(locals()['local_val'])
# グローバルスコープでの locals()
print(locals())
func()
$ python local_function_call_test.py
{'__name__': '__main__', '__spec__': None, '__cached__': None, '__doc__': None, '__builtins__': <module 'builtins' (built-in)>, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x1034bc208>, '__package__': None, 'func': <function func at 0x1034b2950>, '__file__': 'local_function_call_test.py'}
func() is called
{'local_val': 'this is local', 'local_func': <function func.<locals>.local_func at 0x10356c620>}
local_func() is called
this is local
local_func() is called
this is local
ローカル関数、ローカル変数共に文字列で呼び出すことができています
しかし、globals() とは違い呼び出されるブロックによって locals() の内容が変化していることが分かります
(参考) クラス、メソッド、プロパティの動的呼び出し
以下の記事にまとめられています
・Pythonにおけるリフレクション
http://qiita.com/icoxfog417/items/bf04966d4e9706eb9e04
・Pythonによる黒魔術入門
http://www.slideshare.net/ssuser38b704/ll-lang-blackmagic
まとめ
そのスコープで有効になっている関数、変数をチェックするのには使えそうですね
ドキュメントを見る限りでは globals() 静的に決定されるようです
そもそも、フレームワーク等をつくる場合でなければ必要になるかわかりませんが・・・
わけわからなくなるのでメタプログラミングは乱用注意です