2011-02-14 19 views
65

Kiedy lepiej używać zip zamiast itertools.izip?Kiedy lepiej używać zip zamiast zip?

+0

Jednym z powodów na rzecz 'zip', zbyt oczywiste, ale wciąż warto zwrócić uwagę, jest to, że' izip' zwraca 'iterator' które mogą być przemierzanym tylko raz. tj. w 'ii = izip (a, b); f (ii); g (ii) ', tutaj pusta lista' [] 'jest przekazywane do' g'. – Causality

Odpowiedz

33

Gdy wiesz, że chcesz pełną listę skonstruowanych przedmiotów (na przykład do przekazania do funkcji, która zmodyfikowałaby tę listę w miejscu). Lub gdy chcesz zmusić argumenty, które przechodzisz, do zip(), aby były całkowicie ocenione w tym konkretnym punkcie.

+1

Czy nie byłoby lepiej użyć izip w pierwszym przypadku, ponieważ jest szybszy, ponieważ ponownie wykorzystuje krotkę i nie ma prawdziwego powodu, aby nie używać izip? – user1815201

+1

@ user1815201: 'izip' używa ponownie' krotki', jeśli 'krotka' została zwolniona przed rozpoczęciem kolejnej iteracji, więc nic nie zyskuje. Powiedział, że każda strata również jest banalna, więc zgadzam się, że nie ma powodów, aby nie używać wyłącznie 'izip', zawijając' list' jeśli potrzebujesz 'list'; możesz to zrobić w "prawidłowy" sposób, dodając 'from future_builtins import zip' do kodu Py2, który sprawia, że ​​zwykły' zip' w 'izip' (przygotowuje się do przejścia Py3). – ShadowRanger

4

W wersji 2.x, gdy potrzebujesz listę zamiast iteratora.

+0

Czy możesz dać mi przykład, gdzie to może się stać? –

+3

Niezupełnie. Dlatego preferuję 'itertools.izip()', chyba że zyski byłyby czysto statystyczne. –

+2

Jednym z przypadków, gdy potrzebna jest lista, jest sytuacja, w której planujesz uzyskać dostęp do elementów wyniku według indeksu lub musisz znaleźć całkowitą długość. 'lst = zip (lst_a, lst_b)' zezwala na 'lst [1]' lub 'len (lst)'. Jednak dla 'ilst = itertools.izip (lst_a, lst_n)' nie powiedzie się próbując 'ilst [1]' lub 'len (ilst)'. –

79

zip oblicza wszystkie listy na raz, izip oblicza elementy tylko na żądanie.

Jedną ważną różnicą jest to, że „zip” zwraca aktualnej liście „iZIP” zwraca „obiekt iZIP”, który nie jest lista i nie obsługuje funkcji lista specyficznych (takie jak indeksowanie):

>>> l1 = [1, 2, 3, 4, 5, 6] 
>>> l2 = [2, 3, 4, 5, 6, 7] 
>>> z = zip(l1, l2) 
>>> iz = izip(l1, l2) 
>>> isinstance(zip(l1, l2), list) 
True 
>>> isinstance(izip(l1, l2), list) 
False 
>>> z[::2] #Get odd places 
[(1, 2), (3, 4), (5, 6)] 
>>> iz[::2] #Same with izip 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'itertools.izip' object is unsubscriptable 

Tak więc, jeśli potrzebujesz listy (nie jest to obiekt podobny do listy), po prostu użyj "zip".

Poza tym "izip" może być przydatny do zapisywania pamięci lub cykli.

E.g. następujący kod może wyjść po kilku cyklach, więc nie ma potrzeby, aby obliczyć wszystkie elementy listy połączonej:

lst_a = ... #list with very large number of items 
lst_b = ... #list with very large number of items 
#At each cycle, the next couple is provided 
for a, b in izip(lst_a, lst_b): 
    if a == b: 
     break 
print a 

użyciu zip byłby obliczany wszystkie(a, b) pary przed wejściem do cyklu.

Ponadto, jeśli i lst_b są bardzo duże (np. Miliony rekordów), zip(a, b) zbuduje trzecią listę z podwójnym odstępem.

Ale jeśli masz małe listy, być może zip jest szybszy.

+4

Dzięki. Jednak to głównie odpowiada kiedy 'izip' jest lepsze niż' zip' ... –

+6

Masz rację. Zacząłem od dobrych intencji, a potem wpadłem w teoretyczne rzeczy ... – Don

3

Biblioteka itertools udostępnia "iteratory" dla popularnych funkcji Pythona. Z dokumentacji itertools: "Like zip(), ale zwraca iterator zamiast listy." I in w izip() oznacza "iterator".

Iteratory języka Python to sekwencja "leniwy załadowany", który zapisuje pamięć na zwykłej liście w pamięci. Tak więc użyłbyś itertools.izip (a, b), gdy dwa wejścia a, b są zbyt duże, aby utrzymać je w pamięci za jednym razem.

Spójrz pojęcia Python związanych z wydajnego przetwarzania sekwencyjnego:

"generators" & "yield" 
"iterators" 
"lazy loading" 
+0

Ładnie wyjaśniono. –