Was bedeuten ** (Doppelstern/Stern) und * (Stern/Stern) in einem Funktionsaufruf?

Lesezeit: 6 Minuten

Benutzeravatar von psihodelia
Psihodelie

Im Code wie zip(*x) oder f(**k)was machen die * Und ** bzw. bedeuten? Wie implementiert Python dieses Verhalten und was sind die Auswirkungen auf die Leistung?


Siehe auch: Tupel in Argumente erweitern. Bitte verwenden Sie diese, um Fragen zu schließen, bei denen OP verwendet werden muss * auf einen Streit und weiß nicht, dass es existiert.

Siehe Was bewirkt ** (Doppelsternchen/Sternchen) und * (Sternchen/Sternchen) für Parameter? für die ergänzende Frage zu den Parametern.

  • Nachtrag: stackoverflow.com/questions/1141504/…

    – Wds

    27. Mai 2010 um 15:10 Uhr

  • Ich denke, dies sollte als “* Funktionsaufrufsyntax” formuliert werden. Sie sind keine Operatoren, obwohl es dort verwirrend wird Ist A * Und ** Operatoren, die nichts mit dieser Syntax zu tun haben.

    – Ian Bicking

    28. Mai 2010 um 2:45 Uhr

  • @Ian Bicking: Sie haben volles Recht, * und ** in der Argumentliste sind reine Syntax (Token).

    – P. Ortiz

    31. Oktober 2015 um 21:13 Uhr

  • Hinweis: Für PEP 448: Zusätzliche Verallgemeinerungen beim Entpacken bestimmte Sachen (zB [*a, b, *c] oder {**d1, **d2}), sollten Sie Sternchen in Tupel-, Listen- und Set-Definitionen lesen, doppeltes Sternchen in Diktdefinition, was für die Verwendung spezifisch ist außen von Funktionsaufrufen und Funktionsdefinitionen. Für früher PEP 3132siehe Multiple Unpacking Assignment in Python, wenn Sie die Sequenzlänge nicht kennen.

    – ShadowRanger

    22. März 2019 um 20:14 Uhr

Benutzeravatar von Lasse V. Karlsen
Lasse V. Karlsen

Ein einzelner Stern * entpackt eine Sequenz oder Sammlung in Positionsargumente. Angenommen, wir haben

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

values = (1, 2)

Verwendung der * Auspackoperator können wir schreiben s = add(*values)was dem Schreiben entspricht s = add(1, 2).

Der Doppelstern ** macht dasselbe für ein Wörterbuch und liefert Werte für benannte Argumente:

values = { 'a': 1, 'b': 2 }
s = add(**values) # equivalent to add(a=1, b=2)

Beide Operatoren können für denselben Funktionsaufruf verwendet werden. Zum Beispiel gegeben:

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

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

Dann s = add(*values1, **values2) ist äquivalent zu s = sum(1, 2, c=10, d=15).

Siehe auch die entsprechenden Abschnitt des Tutorials in der Python-Dokumentation.


Ähnlich, * Und ** kann für Parameter verwendet werden. Verwenden * ermöglicht einer Funktion, eine beliebige Anzahl von Positionsargumenten zu akzeptieren, die in einem einzigen Parameter gesammelt werden:

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

Wenn die Funktion nun wie aufgerufen wird s = add(1, 2, 3, 4, 5), values wird das Tupel sein (1, 2, 3, 4, 5) (was natürlich das Ergebnis liefert 15).

Ebenso ein mit gekennzeichneter Parameter ** erhält ein dict:

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

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

Dies ermöglicht die Angabe einer großen Anzahl optionaler Parameter, ohne sie deklarieren zu müssen.

Auch hier kann beides kombiniert werden:

def add(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s
        
s = add(1, 2, 3, 4, 5)            # returns 15
s = add(1, 2, 3, 4, 5, neg=True)  # returns -15
s = add(1, 2, 3, 4, 5, neg=False) # returns 15

  • Warum würden Sie das brauchen, könnte die Funktion nicht einfach über die bereitgestellte Liste iterieren, ohne dass sie erweitert wird?

    – Martin Beckett

    27. Mai 2010 um 14:27 Uhr

  • Sicher, aber dann müsste man es nennen: s = sum((1, 2, 3, 4, 5)) oder s = sum([1, 2, 3, 4, 5])Die *values -Option lässt den Aufruf so aussehen, als würde er eine Reihe von Argumenten benötigen, aber sie werden in eine Sammlung für den Funktionscode gepackt.

    – Lasse V. Karlsen

    27. Mai 2010 um 14:29 Uhr

  • Hier ist der eigentliche Vorteil: Sie können Funktionen schreiben, die sonst nicht möglich wären, wenn Sie eine variable Anzahl von Argumenten benötigen. Zum Beispiel ist die C-Funktion printf, die 1+n Argumente hat, als Übung für jeden Programmieranfänger schwierig zu schreiben. In Python kann ein Anfänger def printf(string_template, *args) schreiben und weitermachen.

    – IceArdor

    20. November 2013 um 7:38 Uhr

  • Was passiert, wenn Sie (aus Versehen vielleicht :p) ein Wörterbuch mit nur einem * statt zwei entpacken? Es scheint etwas zu tun, es scheint, als würde ein Tupel herauskommen, aber es ist nicht so offensichtlich, was es ist. (edit: ok, ich denke, die Antwort ist, dass es nur die Schlüssel entpackt, die Werte werden verworfen)

    – Ben Farmer

    15. September 2017 um 7:47 Uhr


  • Das letzte Beispiel impliziert, dass * und ** nicht nur entpacken, sondern auch packen! Sehen Sie sich diese hervorragende Seite an codegame.com/playgrounds/500/…

    – HCChen

    17. Februar 2019 um 4:06 Uhr

Benutzeravatar von sepp2k
sepp2k

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

Bei einer Funktionsdefinition ist es umgekehrt: Der einzelne Stern verwandelt eine beliebige Anzahl von Argumenten in eine Liste, und der Doppelstart verwandelt eine beliebige Anzahl von Schlüsselwortargumenten in ein Wörterbuch. Z.B def foo(*x) bedeutet “foo nimmt eine beliebige Anzahl von Argumenten und sie werden durch zugänglich sein x (dh wenn der Benutzer anruft foo(1,2,3), x wird sein (1, 2, 3))” Und def bar(**k) bedeutet “bar nimmt eine beliebige Anzahl von Schlüsselwortargumenten und sie werden durch zugänglich sein k (dh wenn der Benutzer anruft bar(x=42, y=23), k wird sein {'x': 42, 'y': 23})”.

Benutzeravatar von Donald Miner
Donald Bergmann

Ich finde das besonders nützlich, um Argumente für einen Funktionsaufruf zu speichern.

Angenommen, ich habe einige Komponententests für eine Funktion „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 so etwas wie add(test[0], test[1]), was hässlich ist. Auch wenn es eine variable Anzahl von Variablen gibt, könnte der Code mit all den if-Anweisungen, die Sie benötigen würden, ziemlich hässlich werden.

Ein weiterer nützlicher Ort ist das Definieren von Factory-Objekten (Objekte, die Objekte für Sie erstellen). Angenommen, Sie haben eine Klasse Factory, die Car-Objekte erstellt und zurückgibt. Du könntest es so machen myFactory.make_car('red', 'bmw', '335ix') schafft Car('red', 'bmw', '335ix')gibt es dann zurück.

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

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

  • Ich mag deine Beispiele. Aber ich denke -1 + 3 == 2.

    – eksortso

    27. Mai 2010 um 20:32 Uhr

  • Ich habe absichtlich etwas eingefügt, das fehlschlagen würde 🙂

    – Donald Bergmann

    28. Mai 2010 um 18:15 Uhr

Benutzeravatar von Mark Byers
Markus Byers

Sie wird als erweiterte Aufrufsyntax bezeichnet. Von dem Dokumentation:

Wenn die Syntax *Ausdruck im Funktionsaufruf 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 Ausdruck zu einer Folge y1, …, yM ausgewertet wird, entspricht dies einem Aufruf mit M+N Positionsargumenten x1, …, xN, y1, . .., yM.

Und:

Wenn die Syntax **Ausdruck im Funktionsaufruf erscheint, muss Ausdruck zu einer Zuordnung ausgewertet werden, deren Inhalt als zusätzliche Schlüsselwortargumente behandelt werden. Wenn ein Schlüsselwort sowohl im Ausdruck als auch als explizites Schlüsselwortargument erscheint, wird eine TypeError-Ausnahme ausgelöst.

1449080cookie-checkWas bedeuten ** (Doppelstern/Stern) und * (Stern/Stern) in einem Funktionsaufruf?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy