2010-03-24 11 views
69

OK Uwielbiam funkcję Pythona zip(). Używaj go cały czas, jest genialny. Od czasu do czasu chcę zrobić coś przeciwnego niż zip(), myślę "kiedyś wiedziałem, jak to zrobić", potem wypakowałem google google, a potem zapamiętaj, że używa się tego magicznego * do rozpakowania spakowanej listy krotek. W ten sposób:Dlaczego x, y = zip (* zip (a, b)) działa w języku 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) 

Co się dzieje na ziemi? Co robi ta magiczna gwiazdka? Gdzie indziej można go zastosować i jakie inne niesamowite rzeczy w Pythonie są tak tajemnicze i trudne do Google?

+2

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

+3

oh yeah. Jest to jednak dokładnie problem, przeszukując stackoverflow dla 'zip (*' python nie zwraca zduplikowanego pytania na pierwszej stronie, i google dla 'python *' lub 'python zip (*' nie zwraca zbyt wiele, ponieważ '(*' jest ignorowane? Masz rację, ktoś inny również pomyślał, że to było niesamowite.Należy usunąć pytanie? –

+1

Nie usunąłbym go, ponieważ jest on wyższy w poszukiwaniu z jakiegoś powodu. służy jako przekierowanie –

Odpowiedz

18

Gwiazdka wykonuje oznaczenie apply (tak jak jest to znane w Lisp i Scheme). Zasadniczo bierze twoją listę i wywołuje funkcję z zawartością tej listy jako argumenty.

+1

Seria Python2 ma jeszcze funkcja 'apply', ale nie sądzę, że istnieje są przypadki użycia, których nie można pokryć przez '*'. Wydaje mi się, że został on usunięty z Python3 –

+1

@gnibbler: Confirmed. 'apply' znajduje się na stronie http://www.python.org/dev/peps/pep-0361/ pod nagłówkiem" Ostrzeżenia dotyczące funkcji usuniętych w Py3k: ' – MatrixFrog

+2

Zastosuj istnieje tylko dlatego, że gwiazdka została dodana później. – DasIch

8

Jest także przydatny dla wielu args:

def foo(*args): 
    print args 

foo(1, 2, 3) # (1, 2, 3) 

# also legal 
t = (1, 2, 3) 
foo(*t) # (1, 2, 3) 

I, można użyć podwójną gwiazdką dla argumentów kluczowych i słowniki:

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} 

I oczywiście, można połączyć te:

def foo(*args, **kwargs): 
    print args, kwargs 

foo(1, 2, a=3, b=4) # (1, 2) {'a': 3, 'b': 4} 

Dość schludne i użyteczne rzeczy.

6

To nie zawsze działa:

>>> 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 

Ups! Myślę, że potrzebuje czaszkę przestraszyć go do pracy:

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

W python3 myślę, że trzeba

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

od zip teraz zwraca funkcję generatora, który nie jest fałszywy-y.

+0

Lub po prostu użyj generatora 'unzipped_x = (z [0] dla z w skompresowanym)'. Jeśli 'zipped' sam jest generatorem, należy go najpierw przekonwertować do listy, aby można było ponownie wykonać iterację dla' unzipped_y'. Nie ma żadnych dodatkowych kosztów w porównaniu z 'zip (* zipped)' ponieważ ten ostatni konwertuje również 'zipped' na listę w procesie rozpakowywania argumentów. –

0

Uzupełnienie do użytkownika @ bcherry odpowiedź:

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

Więc to nie działa tylko z argumentów słowa kluczowego (w this strict sense), ale z wymienionych argumentów też (aka pozycyjne argumentów).

2

Jestem nowicjuszem w Pythonie, więc to właśnie ostatnio mnie potknęło, ale musiało to zrobić więcej, gdy przedstawiono przykład i co zostało podkreślone.

To, co dało mi problemy ze zrozumieniem przykładu zip, to asymetria w obsłudze zwracanych wartości wywołania zip. Oznacza to, że gdy zip jest wywoływany po raz pierwszy, zwracana wartość jest przypisywana do pojedynczej zmiennej, tworząc w ten sposób referencję listy (zawierającą utworzoną listę krotek). W drugim wywołaniu wykorzystuje zdolność Pythona do automatycznego rozpakowywania wartości zwracanej przez listę (lub kolekcji?) Do wielu zmiennych referencyjnych, przy czym każde odwołanie jest pojedynczą krotką. Jeśli ktoś nie jest obeznany z tym, jak działa w Pythonie, ułatwia to zagubienie się w tym, co się dzieje.

>>> 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