2010-03-24 2 views
69

OK Ich liebe Pythons zip() Funktion. Benutze es die ganze Zeit, es ist brilliant. Hin und wieder möchte ich das Gegenteil von zip() tun, denke "Ich wusste, wie man das macht", dann google python entpacken, dann erinnere mich, dass man diese magische * verwendet, um eine gezippte Liste von Tupeln zu entpacken. Gefällt mir:Warum funktioniert x, y = zip (* zip (a, b)) in Python?

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 in aller Welt ist los? Was macht dieser magische Stern? Wo sonst kann es angewendet werden und welche anderen fantastischen Dinge in Python sind so mysteriös und schwer zu googeln?

+2

Duplizieren: http://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python –

+3

oh yeah. Dies ist jedoch genau das Problem, Suche stackoverflow für 'zip (*' Python gibt nicht die doppelte Frage auf der ersten Seite, und Googling für 'Python *' oder 'Python zip (*' gibt nicht viel, denke ich, weil das '(*' wird ignoriert? Du hast Recht, jemand anderes dachte auch, das sei genial. Sollte ich die Frage löschen? –

+1

Ich würde es nicht löschen, da es bei der Suche aus irgendeinem Grund höher rangiert es als Umleitung dienen –

Antwort

18

Der Stern führt apply (wie es in Lisp und Scheme bekannt ist). Im Grunde nimmt es Ihre Liste und ruft die Funktion mit dem Inhalt dieser Liste als Argumente auf.

+1

Python2-Serie hat immer noch eine 'apply' Funktion, aber ich denke nicht sind Anwendungsfälle, die nicht durch '*' abgedeckt werden können. Ich glaube, es wurde von Python3 entfernt –

+1

@gnibbler: Bestätigt. 'apply' ist unter http://www.python.org/dev/peps/pep-0361/ unter der Überschrift' Warnungen für in Py3k entfernte Features aufgelistet: ' – MatrixFrog

+2

Übernehmen existiert nur, weil das Sternchen später hinzugefügt wurde. – DasIch

8

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, können Sie zwei Sternchen für die Keyword-Argumente und die 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ützlich Zeug.

6

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 ist ein Schädel es in Arbeits erschrecken muss:

>>> unzipped_x, unzipped_y = zip(*zipped) or ([], []) 
>>> unzipped_x 
[] 
>>> unzipped_y 
[] 

In python3 Ich glaube, Sie

>>> unzipped_x, unzipped_y = tuple(zip(*zipped)) or ([], []) 

müssen seit zip jetzt einen Generator-Funktion gibt, die nicht falsch-y ist.

+0

Oder verwenden Sie einfach einen Generator 'unziped_x = (z [0] für z in gezippt)'. Wenn 'zipped' selbst ein Generator ist, wandle es zuerst in eine Liste um, so dass du erneut für 'unzipped_y' durchgehen kannst. Es gibt keine zusätzlichen Kosten im Vergleich zu 'zip (* zipped)', da letzterer auch "gezippt" in eine Liste konvertiert, während die Argumente entpackt werden. –

0

Nachtrag zum @ bcherry Antwort:

>>> def f(a2,a1): 
... print a2, a1 
... 
>>> d = {'a1': 111, 'a2': 222} 
>>> f(**d) 
222 111 

So funktioniert es nicht nur mit Schlüsselwort-Argumente (in this strict sense), aber mit benannten Argumenten zu (aka Positions Argumente).

2

Ich bin neu bei Python, also hat mich das erst kürzlich verraten, aber es musste mehr mit der Darstellung des Beispiels und dem, was hervorgehoben wurde, machen.

Was gab mir Probleme mit dem Verständnis der Zip-Beispiel war die Asymmetrie in der Handhabung der Zip-Call-Rückgabewert (s). Das heißt, wenn zip das erste Mal aufgerufen wird, wird der Rückgabewert einer einzelnen Variablen zugewiesen, wodurch eine Listenreferenz (mit der erstellten Tupel-Liste) erstellt wird. Im zweiten Aufruf nutzt es die Fähigkeit von Python, einen Rückgabewert einer Liste (oder einer Sammlung?) Automatisch in mehrere Variablenreferenzen zu entpacken, wobei jede Referenz das einzelne Tupel ist. Wenn jemand nicht weiß, wie das in Python funktioniert, ist es einfacher, sich zu 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