OK, ich liebe Pythons zip()
Funktion. Verwenden Sie es die ganze Zeit, es ist brillant. Hin und wieder möchte ich das Gegenteil von zip()
"Ich habe früher gewusst, wie man das macht" machen, dann Google Python entpacken und dann daran denken, dass man diese *
Magie verwendet, um eine komprimierte Liste von Tupeln zu entpacken. 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 dieses magische Sternchen? Wo sonst kann es angewendet werden und welche anderen erstaunlichen Dinge in Python sind so mysteriös und schwer zu googeln?
zip(*
Python durchsuchen, wird die doppelte Frage auf der ersten Seite nicht zurückgegeben, und wenn Sie googelnpython *
oderpython zip(*
nicht viel zurückgeben, denke ich, weil das(*
ignoriert wird. Du hast aber recht, jemand anderes fand das auch großartig. Soll ich die Frage löschen?Antworten:
Das Sternchen in Python ist im Python-Lernprogramm unter Entpacken von Argumentlisten dokumentiert .
quelle
Das Sternchen wird ausgeführt
apply
(wie es in Lisp und Schema bekannt ist). Grundsätzlich nimmt es Ihre Liste und ruft die Funktion mit dem Inhalt dieser Liste als Argumente auf.quelle
apply
Funktion, aber ich glaube nicht, dass es Anwendungsfälle gibt, die nicht abgedeckt werden können*
. Ich glaube, es wurde aus Python3 entferntapply
ist unter python.org/dev/peps/pep-0361 unter der ÜberschriftWarnings for features removed in Py3k:
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)
Außerdem können Sie für Schlüsselwortargumente und Wörterbücher ein doppeltes Sternchen 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 ordentliches und nützliches Zeug.
quelle
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 es zum Arbeiten zu bringen:
>>> unzipped_x, unzipped_y = zip(*zipped) or ([], []) >>> unzipped_x [] >>> unzipped_y []
In Python3 denke ich, dass Sie brauchen
>>> unzipped_x, unzipped_y = tuple(zip(*zipped)) or ([], [])
da zip jetzt eine Generatorfunktion zurückgibt, die nicht False-y ist.
quelle
unzipped_x = (z[0] for z in zipped)
. Wennzipped
es sich selbst um einen Generator handelt, konvertieren Sie ihn zuerst in eine Liste, damit Sie ihn erneut durchlaufen könnenunzipped_y
. Es fallen keine zusätzlichen Kosten an,zip(*zipped)
da letzterezipped
beim Entpacken der Argumente auch in eine Liste konvertiert werden .Ich bin sehr neu in Python, daher hat mich das erst kürzlich gestolpert, aber es hatte mehr damit zu tun, wie das Beispiel präsentiert und was hervorgehoben wurde.
Was mir Probleme beim Verständnis des Zip-Beispiels bereitete, war die Asymmetrie bei der Behandlung der Rückgabewerte des Zip-Anrufs. 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 Tupelliste enthält). Beim zweiten Aufruf wird die Fähigkeit von Python genutzt, einen Listen- (oder Sammlungs-?) Rückgabewert automatisch in mehrere Variablenreferenzen zu entpacken, wobei jede Referenz das einzelne Tupel ist. Wenn jemand nicht weiß, wie das in Python funktioniert, kann er sich leichter darüber verirren, 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
quelle
Nachtrag zu @ bcherrys Antwort:
>>> 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 Sinne ), sondern auch mit benannten Argumenten (auch als Positionsargumente bezeichnet ).
quelle
(x, y) == tuple(zip(*zip(x,y)))
ist genau dann wahr, wenn die beiden folgenden Aussagen wahr sind:x
undy
haben die gleiche Längex
undy
sind TupelEin guter Weg, um zu verstehen, was los ist, ist das Drucken bei jedem Schritt:
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
undy
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
es länger als istx
, hat der erste Zip-Vorgang das zusätzliche Element entfernty
(da es nicht gekoppelt werden konnte), wird diese Änderung offensichtlich beim zweiten Zip-Vorgang erneut ausgeführtzip
wie Paarelemente in Tupeln und nicht in ListenWenn Sie nicht 100% sicher sind, wie es
zip
funktioniert, habe ich hier eine Antwort auf diese Frage geschrieben: Entpacken und der Operator *quelle