Pythonで引数リストを使用して関数を呼び出す


150

Pythonで別の関数内の関数を呼び出そうとしていますが、正しい構文が見つかりません。私がしたいのは次のようなものです:

def wrapper(func, args):
    func(args)

def func1(x):
    print(x)

def func2(x, y, z):
    return x+y+z

wrapper(func1, [x])
wrapper(func2, [x, y, z])

この場合、最初の呼び出しは機能し、2番目は機能しません。変更したいのは、呼び出された関数ではなく、ラッパー関数です。

回答:


268

他の答えを少し拡張するには:

行:

def wrapper(func, *args):

の横の* argsは、「指定された残りのパラメーターを取得し、それらをリストと呼ばれるリストに入れる」ことを意味しますargs

行:

    func(*args)

ここの* argsは、「argsと呼ばれるこのリストを取り、残りのパラメーターに「アンラップ」することを意味します。

したがって、次のことができます。

def wrapper1(func, *args): # with star
    func(*args)

def wrapper2(func, args): # without star
    func(*args)

def func2(x, y, z):
    print x+y+z

wrapper1(func2, 1, 2, 3)
wrapper2(func2, [1, 2, 3])

ではwrapper2、リストは明示的に渡さargsれますが、どちらのラッパーにもリストが含まれています[1,2,3]


26
渡したいリストまたはタプルがある場合、* argsを使用して関数を呼び出す方法については、あまり言及していませんでした。そのためには、次のように呼び出す必要があります。wrapper1(func2、* mylist)
Ali

* args in def wrapper(func, *args)method(params object[] args)C#にあるものです。
ジムアホ2016年

1
*args関数定義の最後の引数でなければならないことに注意してください。
Jim Aho

2
The * next to args means "take the rest of the parameters given and put them in a list called args".リストではなくタプルに入れます。
TomaszNocoń16年

20

関数をラップする最も簡単な方法

    func(*args, **kwargs)

... 内部でfunc()を呼び出すラッパーを手動で作成します。

    def wrapper(*args, **kwargs):
        # do something before
        try:
            return func(*a, **kwargs)
        finally:
            # do something after

Pythonでは関数はオブジェクトなので、別の関数の引数としてその名前を渡して返すことができます。また、任意の関数anyFunc()のラッパージェネレーターを作成することもできます。

    def wrapperGenerator(anyFunc, *args, **kwargs):
        def wrapper(*args, **kwargs):
            try:
                # do something before
                return anyFunc(*args, **kwargs)
            finally:
                #do something after
        return wrapper

Pythonでは、関数のすべての引数がわからない、または名前を付けたくない場合は、引数のタプルを参照できます。これは、その名前で示され、その後に括弧内のアスタリスクが前に付きます。関数名:

    *args

たとえば、任意の数の引数を取る関数を定義できます。

    def testFunc(*args):
        print args    # prints the tuple of arguments

Pythonでは、関数の引数をさらに操作できます。関数がキーワード引数を取ることを許可できます。関数本体内で、キーワード引数は辞書に保持されます。関数名の後の括弧内に、この辞書は2つのアスタリスクとそれに続く辞書の名前で示されます。

    **kwargs

キーワード引数辞書を出力する同様の例:

    def testFunc(**kwargs):
        print kwargs    # prints the dictionary of keyword arguments

11

可変長引数には* argsおよび** kwargs構文を使用できます。

* argsと** kwargsはどういう意味ですか?

そして公式のPythonチュートリアルから

http://docs.python.org/dev/tutorial/controlflow.html#more-on-defining-functions


* argsと** kwargsの両方を取得してそれらを呼び出すには、それが必要ですか?
SurDin 2009年

1
いいえ、どちらかまたは両方を使用できますが、ペアになっていることがよくあります。あなたの場合、必要なのは* argsだけです。
JimB 2009年

はい、動作しますが、それでも引数のリストを渡すことができません。個別に渡す必要があります。私の現在の状況では、それはあまり気になりませんが、これを行う方法を知ることは依然として良いでしょう。(wrapper(func2、[x、y、z])ではな​​く、wrapper(func2、x、y、z)を実行する必要があります)
SurDin

後者が必要な場合は、ラッパーがfunc2を呼び出すときに* args形式を使用しますが、「def wrapper」では使用しません。
Alex Martelli、

10

あなたの質問に対する文字通りの答え(正確にあなたが尋ねたことをするため、ラッパーのみを変更し、関数や関数呼び出しは変更しない)は単に行を変更することです

func(args)

読む

func(*args)

これは、指定されたリスト(この場合はargs)を受け取り、その内容を位置引数として関数に渡すようにPythonに指示します。

このトリックは、関数呼び出しの「両側」で機能するため、関数は次のように定義されます。

def func2(*args):
    return sum(args)

あなたが投げるのと同じくらい多くの位置引数を受け入れ、それらをすべてと呼ばれるリストに入れることができますargs

これが少しわかりやすくなることを願っています。これはの**代わりにを使用して、dicts / keyword引数でもすべて可能です*


8

引数の解凍を使用する必要があります。

def wrapper(func, *args):
    func(*args)

def func1(x):
    print(x)

def func2(x, y, z):
    print x+y+z

wrapper(func1, 1)
wrapper(func2, 1, 2, 3)

0

以前の回答に少し追加しました。問題の解決策を見つけることができなかったためです。これは、新しい質問を開く価値はありませんが、ここに導いてくれました。

以下はlistszip()とを組み合わせた小さなコードスニペット*argsで、未知の量の関数と未知の量の引数を処理できるラッパーを提供します。

def f1(var1, var2, var3):
    print(var1+var2+var3)

def f2(var1, var2):
    print(var1*var2)

def f3():
    print('f3, empty')

def wrapper(a,b, func_list, arg_list):
    print(a)
    for f,var in zip(func_list,arg_list):
        f(*var)
    print(b)

f_list = [f1, f2, f3]
a_list = [[1,2,3], [4,5], []]

wrapper('begin', 'end', f_list, a_list)

それ、覚えておいてzip()、不均等な長さのリストの安全確認を提供見ないジップイテレータはPythonで同じ長さのために主張します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.