Übergeben Sie das Argument ** kwargs an eine andere Funktion mit ** kwargs

152

Ich verstehe das folgende Beispiel nicht, sagen wir, ich habe diese Funktionen:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Warum ist # 1 die richtige Lösung und # 2 die falsche? **kwargsist im Grunde ein Diktat. Wenn ich also das Argument an openX weitergeben möchte, denke ich, wäre der richtige Weg ohne **und nur das Diktat zu geben. Aber Python mag das zweite offensichtlich nicht und sagt mir, dass ich 3 statt 2 Argumente gegeben habe. Was ist der Grund dafür?


quelle
5
Ich frage mich, warum Sie es **argsim Code nennen. Dies ist möglicherweise der schlechteste Name, mit dem die Leute ihn verwechseln werden*args
John La Rooy
1
Nun, ich benutze nie wirklich * args, also benutze ich ** args ^^, aber gut, ich kann es ändern.

Antworten:

155

Im zweiten Beispiel geben Sie drei Argumente an: Dateiname, Modus und ein Wörterbuch ( kwargs). Python erwartet jedoch: 2 formale Argumente plus Schlüsselwortargumente.

Indem Sie dem Wörterbuch '**' voranstellen, entpacken Sie das Wörterbuch kwargsin Schlüsselwortargumente.

Ein Wörterbuch (Typ dict) ist eine einzelne Variable, die Schlüssel-Wert-Paare enthält.

"Schlüsselwortargumente" sind Schlüsselwert-Methodenparameter.

Jedes Wörterbuch kann in Schlüsselwortargumente entpackt werden, indem es **während des Funktionsaufrufs vorangestellt wird .

Gecco
quelle
5
jetzt habe ich es verstanden. Ich dachte, Schlüsselwörter und Diktat wären dasselbe.
13
"Jedes Wörterbuch kann zu Schlüsselwörtern erweitert werden, indem während des Funktionsaufrufs ** vorangestellt wird." <- das ist cool
1
Siehe auch: Python-Dokumente zu Schlüsselwortparametern und zum Entpacken von Argumentlisten
Dinosaurier
8
Ein aktuelles Codebeispiel würde diese Antwort erheblich klarer machen.
OrangeDog
12

Die **Syntax weist Python an, Schlüsselwortargumente in einem Wörterbuch zu sammeln. Das save2gibt es als Nicht-Schlüsselwort-Argument (ein Wörterbuchobjekt) weiter. Das openXsieht keine Schlüsselwortargumente, so dass das **argsnicht verwendet wird. Stattdessen wird ein drittes Argument ohne Schlüsselwort (das Wörterbuch) angezeigt. Um dies zu beheben, ändern Sie die Definition der openXFunktion.

def openX(filename, mode, kwargs):
    pass
Keith
quelle
Vielen Dank, aber ich möchte auch openX ohne Speichern verwenden, also muss ich mich an die Schlüsselwörter halten. Ich dachte, die Weitergabe von Schlüsselwörtern sei im Grunde dasselbe wie die Weitergabe eines Diktats, aber ich wusste es bis jetzt nicht :)
@xMRW Sie können nicht dasselbe sein, da Sie ein Wörterbuch als Parameter auch an eine beliebige Funktion übergeben können. Ihre Nummer 1 ist dann die richtige.
Keith
8

Das folgende Beispiel, das die Antwort von @gecco erweitert, zeigt Ihnen den Unterschied:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Hier können Sie sehen, wie das Entpacken eines Wörterbuchs funktioniert und warum das Senden eines tatsächlichen Wörterbuchs fehlschlägt

Reda Drissi
quelle
1

Weil ein Wörterbuch ein einzelner Wert ist. Sie müssen die Schlüsselworterweiterung verwenden, wenn Sie sie als Gruppe von Schlüsselwortargumenten übergeben möchten.

Ignacio Vazquez-Abrams
quelle
Entschuldigung, aber was ist eine "Keyword-Erweiterung"? Meinst du, ich sollte dict_var anstelle von ** args verwenden und nur def func (argument, dict_var = 0) verwenden ... func (1, {1: "a", 2: "b"})
1

Für # 2 ist args nur ein formaler Parameter mit dict-Wert, jedoch kein Parameter vom Typ Schlüsselwort.

Wenn Sie einen Schlüsselworttyp-Parameter an ein Schlüsselwortargument übergeben möchten, müssen Sie vor Ihrem Wörterbuch ** angeben, was ** Argumente bedeutet

Weitere Informationen zur Verwendung von ** kw finden Sie hier

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

Kit Ho
quelle
Es gibt also einen großen Unterschied zwischen ** kwargs und dict?
danke, ich lese immer gerne mehr über Themen, die ich nicht verstehe.