Die Funktion zip() erschien bereits in Python 2 (damals gab sie eine Liste zurück), und seit Python 3 gibt sie einen faulen Iterator zurück. Sie "verknüpft" mehrere Sequenzen elementweise in Tuples, was die Verarbeitung paralleler iterierbarer Sammlungen bequem und effizient machte.
Es ist oft notwendig, mehrere Listen (oder andere Arten von Sequenzen) gleichzeitig zu verarbeiten – zum Beispiel ein Paar Schlüssel-Wert oder die Koordinaten von Punkt-Paaren zu durchlaufen. Eine eigenständige Synchronisierung von Indizes ist eine Quelle für Fehler und Lesbarkeit des Codes, insbesondere bei Sammlungen unterschiedlicher Länge.
Die Funktion zip() akzeptiert eine beliebige Anzahl von iterierbaren Objekten und gibt einen Iterator von Tuples zurück, wobei jedes Tuple die entsprechenden Elemente jedes Iterable enthält. Wenn die Sequenzen unterschiedlicher Länge sind, wird das Ergebnis am kürzesten abgebrochen.
names = ['Alice', 'Bob', 'Charlie'] ages = [24, 27, 30] for name, age in zip(names, ages): print(f'{name} ist {age} Jahre alt')
Man kann zip mit * entpacken:
pairs = [(1, 'a'), (2, 'b'), (3, 'c')] nums, chars = zip(*pairs) print(nums) # (1, 2, 3) print(chars) # ('a', 'b', 'c')
Was passiert, wenn man zip() Sammlungen unterschiedlicher Länge übergibt?
zip() stoppt, wenn das Ende der kürzesten Sammlung erreicht ist – die übrigen Elemente der längeren Sammlungen werden ignoriert.
print(list(zip([1,2,3], ['a','b']))) # [(1, 'a'), (2, 'b')]
Wie erhält man Tuples, indem man kürzere Sequenzen mit einem Standardwert ergänzt?
Das Standardzip() kann das nicht, aber es gibt itertools.zip_longest für solches Verhalten:
from itertools import zip_longest for a, b in zip_longest([1,2], ['x','y','z'], fillvalue=None): print(a, b) # 1 x # 2 y # None z
Kann man das Ergebnis von zip() "entpacken", um die ursprünglichen Listen zurückzubekommen?
Ja, wenn alle ursprünglichen Sammlungen die gleiche Länge hatten und das Ergebnis nicht verändert wurde, erlaubt der Operator * das Entpacken von zip.
pairs = [(1,2), (3,4)] a, b = zip(*pairs) print(a) # (1, 3) print(b) # (2, 4)
Verarbeitung verbundener Sammlungen unterschiedlicher Länge, ohne die Besonderheiten von zip zu berücksichtigen:
lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip(lst1, lst2): print(x, y) # 1 a # 2 b # (3,4) und 'c', 'd' aus lst1 wurden nicht verarbeitet
Vorteile:
Nachteile:
Verwendung von zip_longest mit fillvalue, um kein Element zu verlieren:
from itertools import zip_longest lst1 = [1,2,3,4] lst2 = ['a','b'] for x, y in zip_longest(lst1, lst2, fillvalue='?'): print(x, y) # 1 a # 2 b # 3 ? # 4 ?
Vorteile:
Nachteile: