Kiedy lepiej jest używać zip zamiast izip?

82

Kiedy lepiej używać zipzamiast itertools.izip?

Neil G.
źródło
Jednym z powodów zip, zbyt oczywistym, ale wciąż wartym podkreślenia, jest to, że izippowraca, przez iteratorktóry można przejść tylko raz. tj. w ii = izip(a,b) ; f(ii) ; g(ii)tym przypadku []przekazywana jest pusta lista g.
Przyczynowość
6
FYI, zipfunkcja Pythona 3 to Python 2 izip. W ogóle Python 3 zmienił większość funkcji do użycia iteratorów, jak zakres, filtr, funkcji DICT, etc
Charles L.

Odpowiedzi:

44

Kiedy wiesz, że będziesz potrzebować pełnej listy skonstruowanych elementów (na przykład do przekazania funkcji, która zmodyfikuje tę listę w miejscu). Lub gdy chcesz zmusić argumenty, do których przechodzisz, zip()aby zostały całkowicie ocenione w tym konkretnym momencie.

Bursztyn
źródło
1
Czy nie byłoby lepiej użyć izipa w pierwszym przypadku, ponieważ jest szybszy, ponieważ ponownie wykorzystuje krotkę i nie ma prawdziwego powodu, aby nie używać izip?
user1815201
1
@ user1815201: izipużywa ponownie tylko tuplewtedy, gdy tuplezostał wydany przed rozpoczęciem następnej iteracji, więc nic Cię nie zyskuje. To powiedziawszy, każda strata jest również trywialna, więc zgadzam się, że nie ma powodu, aby nie używać izipwyłącznie, pakując, listjeśli potrzebujesz list; rzeczywiście można to zrobić na „właściwą” drogę przez dodanie from future_builtins import zipdo kodu PY2, co sprawia, że zwykły zipINTO izip(przygotowanie do Py3 przejścia).
ShadowRanger
99

zipoblicza całą listę naraz, izipoblicza elementy tylko na żądanie.

Jedną ważną różnicą jest to, że „zip” zwraca rzeczywistą listę, „izip” zwraca „obiekt izip”, który nie jest listą i nie obsługuje funkcji specyficznych dla listy (takich 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 (obiektu nie podobnego do listy), po prostu użyj „zip”.

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

Np. Poniższy kod może zakończyć się po kilku cyklach, więc nie ma potrzeby obliczania wszystkich pozycji połączonej listy:

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życie zipspowodowałoby obliczenie wszystkich (a, b) par przed wejściem do cyklu.

Ponadto, jeśli lst_ai lst_bsą bardzo duże (np. Miliony rekordów), zip(a, b)zbuduje trzecią listę z podwójną spacją.

Ale jeśli masz małe listy, może zipjest szybsze.

Don
źródło
9
Masz rację. Zacząłem od dobrych chęci, a potem zająłem się sprawami teoretycznymi ...
Don,
6

Biblioteka itertools zapewnia „iteratory” dla typowych funkcji Pythona. Z dokumentacji itertools: „Podobnie jak zip (), z tą różnicą, że zwraca iterator zamiast listy”. I w izip () oznacza „iterator”.

Iteratory Pythona są sekwencjami „ładowanymi z opóźnieniem”, które oszczędzają pamięć na zwykłej liście w pamięci. Tak więc możesz użyć itertools.izip (a, b), gdy dwa wejścia a, b są zbyt duże, aby przechowywać je w pamięci jednocześnie.

Sprawdź koncepcje Pythona związane z wydajnym przetwarzaniem sekwencyjnym:

"generators" & "yield"
"iterators"
"lazy loading"
Sakib Ahammed
źródło
Ładnie wyjaśnione.
Rahul,
5

W wersji 2.x, gdy potrzebujesz listy zamiast iteratora.

Ignacio Vazquez-Abrams
źródło
Czy możesz podać przykład, gdzie to może się zdarzyć?
Neil G
3
Nie całkiem. Dlatego wolę raczej itertools.izip()z wyjątkiem sytuacji, gdy zyski byłyby czysto statystyczne.
Ignacio Vazquez-Abrams,
2
Jednym z przypadków, gdy potrzebujesz listy, jest planowany dostęp do elementów wyniku według indeksu lub potrzeba znalezienia całkowitej długości. lst = zip(lst_a, lst_b)pozwala lst[1]lub len(lst). Jednak ilst = itertools.izip(lst_a, lst_n)nie uda ci się to zrobić ilst[1]lub len(ilst).
Jan Vlcinsky