web-dev-qa-db-ja.com

Python関数ポインター

次のような変数に関数名を保存しています:

myvar = 'mypackage.mymodule.myfunction'

そして今、私はこのようにmyfunctionを呼び出したい

myvar(parameter1, parameter2)

これを達成する最も簡単な方法は何ですか?

68
schneck
funcdict = {
  'mypackage.mymodule.myfunction': mypackage.mymodule.myfunction,
    ....
}

funcdict[myvar](parameter1, parameter2)

関数自体はPythonのファーストクラスオブジェクトであるため、関数自体を格納できる方がはるかに優れています。

import mypackage

myfunc = mypackage.mymodule.myfunction
myfunc(parameter1, parameter2)

ただし、パッケージを動的にインポートする必要がある場合は、次の方法でこれを実現できます。

mypackage = __import__('mypackage')
mymodule = getattr(mypackage, 'mymodule')
myfunction = getattr(mymodule, 'myfunction')

myfunction(parameter1, parameter2)

ただし、その作業はすべて現在のスコープに適用されることに注意してください。何らかの理由でそれらを永続化しないと、ローカルスコープを離れてもそれらが存続することを期待できません。

35
user609095
def f(a,b):
    return a+b

xx = 'f'
print eval('%s(%s,%s)'%(xx,2,3))

[〜#〜] output [〜#〜]

 5
12
Pratik Deoghare

最も簡単な

eval(myvar)(parameter1, parameter2)

関数「ポインター」がありません。関数「名前」があります。

これはうまく機能しますが、「安全ではない」または「セキュリティリスク」であると多くの人に言われます。

8
S.Lott

関数自体を保存しないのはなぜですか? myvar = mypackage.mymodule.myfunctionはずっときれいです。

5
ironfroggy
modname, funcname = myvar.rsplit('.', 1)
getattr(sys.modules[modname], funcname)(parameter1, parameter2)
4
Matt Anderson

eval(compile(myvar,'<str>','eval'))(myargs)

compile(...、 'eval')は単一のステートメントのみを許可するため、呼び出し後に任意のコマンドを使用することはできません。そうしないと、SyntaxErrorが発生します。その後、ほんの少しの検証で、少なくとも「mypackage」のテストを開始するなど、表現をあなたの力のあるものに制約することができます。

2
SilverbackNet

認証を処理するライブラリを作成中に、同様の問題に遭遇しました。ライブラリを使用するアプリの所有者が、認証されたユーザーが属するLDAPグループに対する承認をチェックするためにライブラリにコールバックを登録できるようにしたいです。設定は、インポートされ、すべての構成パラメーター。

私はこれを機能させました:

>>> class MyClass(object):
...     def target_func(self):
...         print "made it!"
...    
...     def __init__(self,config):
...         self.config = config
...         self.config['funcname'] = getattr(self,self.config['funcname'])
...         self.config['funcname']()
... 
>>> instance = MyClass({'funcname':'target_func'})
made it!

これを行うPythonic-erの方法はありますか?

2
Rob Fagen