Edited at

Python - 関数を文字列から動的に呼び出す

More than 3 years have passed since last update.

Python で文字列から動的に関数を呼び出す方法について

メソッドやプロパティの動的呼び出しはいくつか解説があったんですが、

グローバル関数や変数の動的呼び出しのやり方がわからなかったので調べました


eval()

eval() を実行すると引数で渡した文字列が Python コードとして評価されます

それを利用して、文字列から任意の関数、変数の値を文字列から呼び出すことができます

公式ドキュメント

http://docs.python.jp/3.5/library/functions.html#eval

こんな感じで使います


eval_test.py

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

こんな感じで使います


function_call_test.py

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


local_function_call_test.py

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() 静的に決定されるようです

そもそも、フレームワーク等をつくる場合でなければ必要になるかわかりませんが・・・

わけわからなくなるのでメタプログラミングは乱用注意です