名前(文字列)を使用してモジュールの関数を呼び出す


1735

Pythonプログラムで関数の名前を持つ文字列を指定して関数を呼び出すための最良の方法は何ですか。たとえば、モジュールfooがあり、コンテンツがである文字列があるとし"bar"ます。電話する最良の方法は何foo.bar()ですか?

関数の戻り値を取得する必要があるため、だけを使用しませんevaleval関数呼び出しの結果を返す一時関数を定義するためにを使用してそれを行う方法を理解しましたが、これを行うよりエレガントな方法があることを期待しています。

回答:


2079

fooメソッドを持つモジュールを想定bar

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

2行目と3行目を次のように短縮できます。

result = getattr(foo, 'bar')()

それがあなたのユースケースにとってより理にかなっている場合。

あなたが使用することができgetattr、クラスのインスタンスバインド方法、モジュールレベルのメソッド、クラスメソッドでこのやり方で...リストに載っています。


9
hasattrまたはgetattrを使用して、関数が定義されているかどうかを判別できます。私はデータベースマッピング(eventTypeとfunctionNameの処理)を持っていて、Pythonでイベントハンドラーを定義するのを「忘れない」ようにしたかったのです
Shaun

9
これは、モジュール名がわかっている場合に機能します。ただし、ユーザーにモジュール名を文字列として提供させたい場合、これは機能しません。
Blairg23 2014年

7
NoneTypeを呼び出せない例外を回避する必要がある場合は、3つの引数の形式のgetattr:getattr(foo、 'bar'、lambda:None)を使用することもできます。フォーマットについてお詫び申し上げます。stackexchange androidアプリは明らかにひどいです。
geekofalltrades 2014

3
ローカル/現在のモジュールの機能だけを例に考えている場合は、@ sastaninが提供する回答も参照してください。
NuSkooler 2015年

6
はい@akki、あなたがしている場合fooモジュールを使用できglobals()、これを行うために:methodToCall = globals()['bar']
ベン・ホイト

543
locals()["myfunction"]()

または

globals()["myfunction"]()

localsは、現在のローカルシンボルテーブルを持つディクショナリを返します。globalsは、グローバルシンボルテーブルを含む辞書を返します。


53
グローバル/ローカルを使用するこのメソッドは、呼び出す必要があるメソッドが、呼び出し元と同じモジュールで定義されている場合に適しています。
Joelmob 2014年

@ジョエルモブはルート名前空間から文字列でオブジェクトを取得する他の方法はありますか?
Nick T

@NickT私はこれらのメソッドのみを認識しています。これらと同じ機能を満たす他のメソッドはないと思います。少なくとも、もっと必要な理由は考えられません。
Joelmob、2015年

私にはあなたに理由があります(実際にここで私を導いたもの):モジュールAには、関数を名前で呼び出す必要がある関数Fがあります。モジュールBはモジュールAをインポートし、モジュールBで定義されている関数Gを呼び出す要求で関数Fを呼び出します。関数FはモジュールFで定義されているグローバルでのみ実行されるため、この呼び出しは失敗します-globals() ['G'] =なし。
David Stein

337

パトリックのソリューションはおそらく最もクリーンです。モジュールも動的に取得する必要がある場合は、次のようにインポートできます。

module = __import__('foo')
func = getattr(module, 'bar')
func()

93
最後のコメントはわかりません。__import__には独自の権利があり、前述のドキュメントの次の文は、「名前が実行時にのみ既知であるモジュールをインポートする場合を除いて、__ import __()を直接使用することはまれです」と述べています。だから:与えられた答えの+1。
hoffmaje

50
を使用しimportlib.import_moduleます。公式ドキュメントはこう述べてい__import__ます:「これはimportlib.import_module()とは異なり、日常のPythonプログラミングでは必要のない高度な関数です。」docs.python.org/2/library/functions.html#__import__
glarrain

8
@glarrain 2.7以降のみをサポートしていれば問題ありません。
Xiong Chiamiov 2013

1
@Xiong Chaimiov importlib.import_moduleは3.6でサポートされています。docs.python.org/3.6/library/…を
カウリネーター

7
@cowlinatorはい、3.6は厳密なバージョン管理のセマンティクスとリリース日(約6年後)の両方で、「2.7以降」の一部です。また、私のコメントから3年間は存在しませんでした。;)3.xブランチでは、モジュールは3.1以降に存在します。2.7と3.1は現在かなり古いものです。2.6のみをサポートしているサーバーがまだぶら下がっていますが、今日の標準的なアドバイスはimportlibにすることです。
Xiong Chiamiov 2017年

114

単純な貢献。インスタンス化する必要があるクラスが同じファイル内にある場合は、次のようなものを使用できます。

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

例えば:

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

そして、クラスでない場合:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')

101

関数への完全なpythonパスを含む文字列が与えられた場合、これは私が上記の関数の結果を取得する方法でした:

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()

1
これは私を助けました。その軽量バージョンの__import__関数です。
Pankaj Bhambhani

これが最良の答えだったと思います。
サイード

55

PythonプログラミングFAQによる最良の答えは次のとおりです。

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

この手法の主な利点は、文字列が関数の名前と一致する必要がないことです。これは、ケースコンストラクトをエミュレートするために使用される主要な手法でもあります。


43

答え(私は願っています)誰も望んでいない

評価のような動作

getattr(locals().get("foo") or globals().get("foo"), "bar")()

自動インポートを追加しないのはなぜですか

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

確認したい追加の辞書がある場合

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

もっと深く行く必要がある

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()

これは再帰的にディレクトリツリーと自動マウントUSBドライブをスキャンすることによって改善することができた
ウィルクス

27

価値があるのは、関数(またはクラス)の名前とアプリ名を文字列として渡す必要がある場合は、次のようにすることです。

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

もう少し一般的ですhandler = getattr(sys.modules[__name__], myFnName)
lony

21

これを試して。これはまだevalを使用しますが、現在のコンテキストから関数呼び出すためにのみ使用します。次に、あなたが望むように使用するための本当の機能を持っています。

これによる私にとっての主な利点は、関数を呼び出す時点でeval関連のエラーが発生することです。次に、呼び出し時に関数関連のエラーのみが表示されます。

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)

1
これは危険です。stringは何でも持つことができ、evalは何も考慮せずにevalを実行します。
iankit 16

4
確かに、これらのリスクを考慮して、これが適切かどうかに関係なく、使用するコンテキストに注意する必要があります。
tvt173

1
関数は、そのパラメーターの検証を担当するべきではありません-それは別の関数の仕事です。文字列でevalを使用するのは危険だと言っているのは、すべての関数を使用するのが危険だということです。
red777 2018

eval厳密に必要な場合を除いて、使用しないでください。getattr(__module__, method_name)このコンテキストでは、はるかに良い選択です。
moi

14

提案されたものはどれも私を助けませんでした。私はこれを発見しました。

<object>.__getattribute__(<string name>)(<params>)

私はpython 2.66を使用しています

お役に立てれば


13
これはどの点でgetattr()より優れていますか?
V13 2013

1
まさに私が欲しかったもの。魅力的な作品!パーフェクト!! self.__getattribute__('title')と等しいself.title
ioaniatr

self.__getattribute__('title')結局のところ(理由がわからない)どのケースでも機能しませんが、func = getattr(self, 'title'); func();機能します。そのため、getattr()代わりに使用する方が良いかもしれません
ioaniatr

10
Pythonを知らない人は、このジャンクへの賛成をやめてください。getattr代わりに使用してください。
2018

6

この質問として、変数へのメソッド名の割り当てを使用してクラス内のメソッドを動的に呼び出す方法[複製]としてのとして、この重複としてマークされているため、ここに関連する回答を投稿しています:

シナリオは、クラスのメソッドが同じクラスの別のメソッドを動的に呼び出したい場合です。元の例にいくつかの詳細を追加して、より幅広いシナリオと明確さを提供しています。

class MyClass:
    def __init__(self, i):
        self.i = i

    def get(self):
        func = getattr(MyClass, 'function{}'.format(self.i))
        func(self, 12)   # This one will work
        # self.func(12)    # But this does NOT work.


    def function1(self, p1):
        print('function1: {}'.format(p1))
        # do other stuff

    def function2(self, p1):
        print('function2: {}'.format(p1))
        # do other stuff


if __name__ == "__main__":
    class1 = MyClass(1)
    class1.get()
    class2 = MyClass(2)
    class2.get()

出力(Python 3.7.x)

機能1:12

機能2:12


-7

これは簡単な答えです。これにより、たとえば画面をクリアできます。以下の2つの例があります。evalとexecを使用して、クリーニング後(Windowsを使用している場合はに変更clearcls、LinuxとMacのユーザーはそのままにしておくなど)または実行するだけで、それぞれ0を出力します。

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")

3
これはopが要求するものではありません。
TuncayGöncüoğlu19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.