OK, ich liebe die Zip()
-Funktion von Python. Verwenden Sie es die ganze Zeit, es ist brillant. Hin und wieder möchte ich das Gegenteil von Zip()
tun, denke "Ich wusste, wie man das macht", dann Google Python entpacken und dann daran denken, dass man mit diesem magischen *
eine gezippte Liste von Tupeln entpackt. So was:
x = [1,2,3]
y = [4,5,6]
zipped = Zip(x,y)
unzipped_x, unzipped_y = Zip(*zipped)
unzipped_x
Out[30]: (1, 2, 3)
unzipped_y
Out[31]: (4, 5, 6)
Was zu Hölle ist hier los? Was macht das magische Sternchen? Wo sonst kann es angewendet werden und welche anderen erstaunlichen Dinge in Python sind so geheimnisvoll und schwer zu googeln?
Das Sternchen in Python ist im Python-Lernprogramm unter Argumentlisten entpacken dokumentiert.
Das Sternchen führt apply
aus (wie in LISP und Scheme bekannt). Im Grunde nimmt es Ihre Liste und ruft die Funktion mit dem Inhalt dieser Liste als Argumente auf.
Es ist auch nützlich für mehrere Argumente:
def foo(*args):
print args
foo(1, 2, 3) # (1, 2, 3)
# also legal
t = (1, 2, 3)
foo(*t) # (1, 2, 3)
Und Sie können ein Doppelsternchen für Schlüsselwortargumente und Wörterbücher verwenden:
def foo(**kwargs):
print kwargs
foo(a=1, b=2) # {'a': 1, 'b': 2}
# also legal
d = {"a": 1, "b": 2}
foo(**d) # {'a': 1, 'b': 2}
Und natürlich können Sie diese kombinieren:
def foo(*args, **kwargs):
print args, kwargs
foo(1, 2, a=3, b=4) # (1, 2) {'a': 3, 'b': 4}
Ziemlich ordentlich und nützliche Sachen.
Es funktioniert nicht immer:
>>> x = []
>>> y = []
>>> zipped = Zip(x, y)
>>> unzipped_x, unzipped_y = Zip(*zipped)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
Hoppla! Ich denke, es braucht einen Schädel, um die Arbeit zu erschrecken:
>>> unzipped_x, unzipped_y = Zip(*zipped) or ([], [])
>>> unzipped_x
[]
>>> unzipped_y
[]
In Python3 denke ich, du brauchst
>>> unzipped_x, unzipped_y = Tuple(Zip(*zipped)) or ([], [])
da Zip jetzt eine Generatorfunktion zurückgibt, die nicht False-y ist.
Ich bin extrem neu in Python, also hat mich das erst vor kurzem in die Knie gezwungen, aber es musste mehr damit zu tun haben, wie das Beispiel dargestellt wurde und was hervorgehoben wurde.
Was mir beim Verstehen des Zip-Beispiels Probleme bereitete, war die Asymmetrie bei der Handhabung der Zip-Rückgabewerte. Das heißt, wenn Zip zum ersten Mal aufgerufen wird, wird der Rückgabewert einer einzelnen Variablen zugewiesen, wodurch eine Listenreferenz erstellt wird (die die erstellte Tupel-Liste enthält). Beim zweiten Aufruf wird die Fähigkeit von Python genutzt, einen Listenwert (oder eine Sammlung?) Automatisch in mehrere Variablenreferenzen zu entpacken, wobei jede Referenz der einzelne Tuple ist. Wenn jemand mit der Funktionsweise von Python nicht vertraut ist, ist es einfacher, sich zu verlieren, was tatsächlich passiert.
>>> x = [1, 2, 3]
>>> y = "abc"
>>> zipped = Zip(x, y)
>>> zipped
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> z1, z2, z3 = Zip(x, y)
>>> z1
(1, 'a')
>>> z2
(2, 'b')
>>> z3
(3, 'c')
>>> rezipped = Zip(*zipped)
>>> rezipped
[(1, 2, 3), ('a', 'b', 'c')]
>>> rezipped2 = Zip(z1, z2, z3)
>>> rezipped == rezipped2
True
(x, y) == Tuple(Zip(*Zip(x,y)))
ist genau dann wahr, wenn die beiden folgenden Aussagen wahr sind:
x
und y
haben die gleiche Längex
und y
sind TupelEin guter Weg, um zu verstehen, was vor sich geht, ist, bei jedem Schritt zu drucken:
x = [1, 2, 3]
y = ["a", "b", "c", "d"]
print("1) x, y = ", x, y)
print("2) Zip(x, y) = ", list(Zip(x, y)))
print("3) *Zip(x, y) = ", *Zip(x, y))
print("4) Zip(*Zip(x,y)) = ", list(Zip(*Zip(x,y))))
Welche Ausgänge:
1) x, y = [1, 2, 3] ['a', 'b', 'c', 'd']
2) Zip(x, y) = [(1, 'a'), (2, 'b'), (3, 'c')]
3) *Zip(x, y) = (1, 'a') (2, 'b') (3, 'c')
4) Zip(*Zip(x,y)) = [(1, 2, 3), ('a', 'b', 'c')]
Grundsätzlich passiert folgendes:
x
und y
werden entsprechend ihren jeweiligen Indizes gepaart.(1, 2, 3)
('a', 'b', 'c')
Jetzt können Sie verstehen, warum (x, y) == Tuple(Zip(*Zip(x,y)))
in diesem Fall falsch ist:
y
länger als x
ist, hat der erste Zip-Vorgang das zusätzliche Element aus y
entfernt (da es nicht gepaart werden konnte). Diese Änderung wird offensichtlich beim zweiten Zip-Vorgang erneut durchgeführtZip
Elemente in Tupeln und nicht in Listen paartWenn Sie nicht zu 100% sicher sind, wie Zip
funktioniert, habe ich hier eine Antwort auf diese Frage geschrieben: Entpacken und der Operator *
Nachtrag zur Antwort von @ bcherry:
>>> def f(a2,a1):
... print a2, a1
...
>>> d = {'a1': 111, 'a2': 222}
>>> f(**d)
222 111
Es funktioniert also nicht nur mit Schlüsselwortargumenten (in diesem strengen Sinn ), sondern auch mit benannten Argumenten (aka positional -Argumenten).