LoginSignup
122
96

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-06-13

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

そもそも、フレームワーク等をつくる場合でなければ必要になるかわかりませんが・・・
わけわからなくなるのでメタプログラミングは乱用注意です

122
96
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
122
96