関数呼び出しで、スター演算子はどういう意味ですか?


630

*ようなコードzip(*x)やのようなPythonでの演算子の意味は何f(**k)ですか?

  1. インタプリタの内部でどのように処理されますか?
  2. パフォーマンスにまったく影響しますか?速いですか遅いですか?
  3. いつ役に立ち、いつ役に立たないのですか?
  4. 関数宣言または呼び出しで使用する必要がありますか?


4
これは「*関数呼び出し構文」と表現する必要があると思います。これらは演算子ではありませんが、この構文とは関係のないand演算子あるため、混乱します。***
Ian Bicking 2010年

1
@Ian Bicking:あなたは完全に正しいです。引数リストの*と**は純粋な構文(トークン)です。
P. Ortiz

2
注:PEP 448:Additional Unpacking Generalizations固有のもの([*a, b, *c]または{**d1, **d2})の場合、タプルのアスタリスク、リストとセットの定義、dict定義の二重アスタリスクを読む必要があります。これは関数呼び出しと関数定義以外の使用に固有です。。以前のPEP3132については、シーケンスの長さがわからない場合のPythonでの複数の解凍割り当てを参照してください。
ShadowRanger

1
VTR-これは、**(二重星/アスタリスク)と*(星/アスタリスク)がパラメーターに対して行うことの複製ではありませんか?答えは関数呼び出しもカバーしていますが、その質問はパラメーターのみに関するものです。関数呼び出しのアスタリスクは、あまり人気がなく、上位の回答が不完全であるため、この質問の重複としてマークする必要があります。
wjandrea

回答:


965

単一の星*は、シーケンス/コレクションを位置引数に解凍するため、次のことができます。

def sum(a, b):
    return a + b

values = (1, 2)

s = sum(*values)

これにより、タプルが解凍され、実際には次のように実行されます。

s = sum(1, 2)

二重星**は同じことを行いますが、辞書と名前付き引数のみを使用します。

values = { 'a': 1, 'b': 2 }
s = sum(**values)

以下を組み合わせることもできます。

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)

次のように実行されます:

s = sum(1, 2, c=10, d=15)

セクション4.7.4- Pythonドキュメントの引数リストの解凍も参照してください。


さらに、取る関数*x**y引数を定義できます。これにより、関数は、宣言で具体的に指定されていない任意の数の位置引数や名前付き引数を受け入れることができます。

例:

def sum(*values):
    s = 0
    for v in values:
        s = s + v
    return s

s = sum(1, 2, 3, 4, 5)

またはと**

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # returns 1

これにより、宣言せずに多数のオプションパラメータを指定できます。

そして再び、あなたは組み合わせることができます:

def sum(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s

s = sum(1, 2, 3, 4, 5)            # returns 15
s = sum(1, 2, 3, 4, 5, neg=True)  # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15

4
なぜこれが必要なのですか、関数は拡張されずに提供されたリストを繰り返すことができませんでしたか?
マーティンベケット2010年

30
もちろんですが、それを呼び出す必要があります。s = sum((1, 2, 3, 4, 5))またはs = sum([1, 2, 3, 4, 5])、この*valuesオプションを使用すると、呼び出しはいくつかの引数を取るように見えますが、それらは関数コードのコレクションにパックされています。
Lasse V. Karlsen

12
これが本当の利点です。可変数の引数が必要な場合、他の方法では不可能な関数を記述できます。たとえば、1 + n個の引数を持つCのprintf関数は、初心者のプログラマーの演習として書くのが難しいです。Pythonでは、初心者はdef printf(string_template、* args)を記述して、先に進むことができます。
IceArdor 2013年

1
(偶然に:p)辞書を2つではなく1つだけで解凍するとどうなりますか?何かをしているようで、タプルが出ているように見えますが、それが何であるかはそれほど明白ではありません。(編集:わかりました、答えはキーを解凍するだけで、値は破棄されると思います)
ベンファーマー

1
最後の例は、*と**が開梱だけでなく梱包も行っていることを示しています。この優れたページを参照してくださいcodingame.com/playgrounds/500/...
HCChen

46

1つの小さなポイント:これらは演算子ではありません。演算子は、既存の値から新しい値を作成するために式で使用されます(たとえば、1 + 2は3になります。ここでの*と**は、関数宣言と呼び出しの構文の一部です。


7
Pythonのドキュメントでは、このコンテキストでは*を演算子と呼んでいることに注意してください。私は同意します、それは一種の誤解を招くものです。
クリストフ

ありがとう。私はPythonのリファレンスドキュメントでこれの明確な説明を探していましたが、まだ表示されていません。したがって、関数呼び出しのルールは、基本的に、関数呼び出し内の式の先頭にある「*」または「**」がこの種の展開を引き起こすということですか?
nealmcb 2012年

21

これは、関数呼び出しを「保存」する場合に特に便利です。

たとえば、関数 'add'の単体テストがあるとします。

def add(a, b): return a + b
tests = { (1,4):5, (0, 0):0, (-1, 3):3 }
for test, result in tests.items():
   print 'test: adding', test, '==', result, '---', add(*test) == result

add(test [0]、test [1])のような醜いことを手動で行う以外に、addを呼び出す方法はありません。また、変数の数が可変である場合、必要なすべてのifステートメントでコードがかなり醜くなる可能性があります。

これが役立つもう1つの場所は、ファクトリオブジェクト(オブジェクトを作成するオブジェクト)を定義する場合です。Carオブジェクトを作成して返すクラスFactoryがあるとします。myFactory.make_car( 'red'、 'bmw'、 '335ix')がCar( 'red'、 'bmw'、 '335ix')を作成し、それを返すようにすることができます。

def make_car(*args):
   return Car(*args)

これは、スーパークラスのコンストラクターを呼び出す場合にも役立ちます。


4
私はあなたの例が好きです。しかし、私が思うに-1 + 3 == 2
eksortso

5
私は意図的に失敗する何かをそこに入れました:)
ドナルドマイナー2010年

19

これは、拡張呼び出し構文と呼ばれます。ドキュメントから:

構文* expressionが関数呼び出しに含まれている場合、expressionはシーケンスに評価される必要があります。このシーケンスの要素は、追加の位置引数であるかのように扱われます。位置引数x1、...、xNがあり、式がシーケンスy1、...、yMに評価される場合、これはM + N位置引数x1、...、xN、y1、...を使用した呼び出しと同等です。 ..、yM。

そして:

構文**式が関数呼び出しに含まれている場合、式はマッピ​​ングに評価される必要があり、その内容は追加のキーワード引数として扱われます。式と明示的なキーワード引数の両方にキーワードが表示される場合、TypeError例外が発生します。


3
ただ、教科書の答えに脚注を追加する-構文のサポートが到着する前に、同じ機能が内蔵されて達成されたapply()機能
ジェレミー・ブラウン

18

関数呼び出しでは、単一の星は、(例えば別々の引数にリストを回すzip(*x)と同じであるzip(x1,x2,x3)場合はx=[x1,x2,x3]例えば()と二重星は、別々のキーワード引数に辞書を回すf(**k)と同じであるf(x=my_x, y=my_y)場合k = {'x':my_x, 'y':my_y}

関数定義では、その逆です。単一のスターは任意の数の引数をリストに変換し、ダブルスタートは任意の数のキーワード引数を辞書に変換します。たとえばdef foo(*x)、「fooは任意の数の引数を取り、リストxからアクセスできます(つまり、ユーザーがを呼び出すとfoo(1,2,3)、にxなります[1,2,3])」をdef bar(**k)意味し、「barは任意の数のキーワード引数を取り、辞書kからアクセスできる」ことを意味します。 (ユーザー・コール場合、すなわちbar(x=42, y=23)kだろう{'x': 42, 'y': 23}「)。


3
(非常に)遅いコメントですが、def foo(*x)* xからはリストではなくタプルが得られると思います。
jeremycg 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.