Was bedeutet der Sternoperator?

Mögliche Duplikate:
Was bedeuten * Args und ** Kwargs?

Was bedeutet der Operator * in Python, etwa in Code wie zip(*x) oder f(**k) ?

  1. Wie wird intern im Interpreter verfahren?
  2. Beeinflusst es überhaupt die performance? Ist es schnell oder langsam?
  3. Wann ist es sinnvoll und wann nicht?
  4. Soll es in einer functionsdeklaration oder in einem Aufruf verwendet werden?

Der einzelne Stern * entpackt die Sequenz / Sammlung in Positionsargumente, so dass Sie dies tun können:

 def sum(a, b): return a + b values = (1, 2) s = sum(*values) 

Dies entpackt das Tupel so, dass es tatsächlich ausgeführt wird als:

 s = sum(1, 2) 

Der Doppelstern ** macht dasselbe, nur mit einem Wörterbuch und so genannten Argumenten:

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

Sie können auch kombinieren:

 def sum(a, b, c, d): return a + b + c + d values1 = (1, 2) values2 = { 'c': 10, 'd': 15 } s = sum(*values1, **values2) 

wird ausgeführt als:

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

Siehe auch Abschnitt 4.7.4 – Entpacken von Argumentlisten der Python-Dokumentation.


Zusätzlich können Sie functionen definieren, die *x und **y Argumente annehmen. Dadurch kann eine function eine beliebige Anzahl von positionellen und / oder benannten Argumenten akzeptieren, die in der Deklaration nicht speziell benannt sind.

Beispiel:

 def sum(*values): s = 0 for v in values: s = s + v return s s = sum(1, 2, 3, 4, 5) 

oder mit ** :

 def get_a(**values): return values['a'] s = get_a(a=1, b=2) # returns 1 

Dadurch können Sie eine große Anzahl von optionalen Parametern angeben, ohne sie deklarieren zu müssen.

Und wieder können Sie kombinieren:

 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 

Ein kleiner Punkt: Das sind keine Operatoren. Operatoren werden in Ausdrücken verwendet, um neue Werte aus vorhandenen Werten zu erstellen (1 + 2 wird beispielsweise zu 3. Die * und ** sind hier Teil der Syntax von functionsdeklarationen und -aufrufen.

Es wird die erweiterte Aufrufsyntax genannt. Aus der Dokumentation :

Wenn der Syntaxausdruck im functionsaufruf erscheint, muss Ausdruck zu einer Sequenz ausgewertet werden. Elemente aus dieser Sequenz werden behandelt, als wären sie zusätzliche Positionsargumente; Wenn Positionsargumente x1, …, xN vorhanden sind und der Ausdruck zu einer Sequenz y1, …, yM ausgewertet wird, entspricht dies einem Aufruf mit M + N Positionsargumenten x1, …, xN, y1,. .., yM.

und:

Wenn der Ausdruck der Syntax ** im functionsaufruf erscheint, muss Ausdruck zu einem Mapping ausgewertet werden, dessen Inhalt als zusätzliche Schlüsselwortargumente behandelt wird. Im Fall eines Schlüsselworts, das sowohl in Ausdruck als auch als explizites Schlüsselwortargument angezeigt wird, wird eine TypeError-Ausnahme ausgetriggers.

Ich finde das besonders nützlich, wenn Sie einen functionsaufruf “speichern” wollen.

Angenommen, ich habe einige Komponententests für eine function ‘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 

Es gibt keine andere Möglichkeit, add aufzurufen, als manuell etwas wie add (test [0], test [1]) zu tun, was hässlich ist. Wenn es eine variable Anzahl von Variablen gibt, könnte der Code mit all den if-statementen, die Sie benötigen, ziemlich hässlich werden.

Ein weiterer nützlicher Platz ist das Definieren von Factory-Objekten (Objekte, die Objekte für Sie erstellen). Angenommen, Sie haben eine class Factory, die Car-Objekte erzeugt und zurückgibt. Sie können es so machen, dass myFactory.make_car (‘red’, ‘bmw’, ‘335ix’) Auto (‘red’, ‘bmw’, ‘335ix’) erstellt und es dann zurückgibt.

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

Dies ist auch nützlich, wenn Sie den Konstruktor einer Superklasse aufrufen möchten.

In einem functionsaufruf verwandelt der einzelne Stern eine Liste in separate Argumente (z. B. ist zip(*x) gleich wie zip(x1,x2,x3) wenn x=[x1,x2,x3] ) und der Doppelstern ein Wörterbuch dreht in separate Schlüsselwortargumente (zB f(**k) ist dasselbe wie f(x=my_x, y=my_y) wenn k = {'x':my_x, 'y':my_y} .

In einer functionsdefinition ist es umgekehrt: Der einzelne Stern wandelt eine beliebige Anzahl von Argumenten in eine Liste um, und der doppelte Start verwandelt eine beliebige Anzahl von Schlüsselwortargumenten in ein Wörterbuch. ZB def foo(*x) bedeutet “foo nimmt eine beliebige Anzahl von Argumenten und sie sind über die Liste x zugänglich (dh wenn der Benutzer foo(1,2,3) aufruft, wird x [1,2,3] ) “und def bar(**k) bedeutet, dass” bar “eine beliebige Anzahl von Schlüsselwortargumenten enthält und über das Wörterbuch k zugänglich ist (dh wenn der Benutzer bar(x=42, y=23) aufruft, wird k {'x': 42, 'y': 23} ) “.