ProgrammierungBackend-Entwickler

Wie funktioniert die eingebaute Funktion zip() in Python, wozu wird sie verwendet und welche Feinheiten gibt es bei der Verarbeitung von Sequenzen unterschiedlicher Länge?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Geschichte der Frage

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.

Problem

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.

Lösung

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.

Beispielcode:

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

Hauptmerkmale:

  • zip() gibt einen Iterator (in Python 3) und keine Liste zurück.
  • Die Arbeit von zip() bricht am kürzesten Iterable ab.
  • Ermöglicht die parallele Verarbeitung von Sammlungen ohne explizite Kontrolle der Indizes.

Fangfragen.

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)

Typische Fehler und Anti-Pattern

  • Erwarten, dass zip() immer bis zum Ende der längsten Sammlung "kommt".
  • Annehmen, dass zip() in Python 3 eine Liste zurückgibt (es ist ein Iterator, manchmal muss man es in list() einwickeln).
  • Mit zip bei veränderlichen Quellen arbeiten, die bei jeder Iteration verbraucht werden.

Beispiel aus dem Leben

Negativer Fall

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:

  • Einfach und verständlich, wenn die Sequenzen garantiert von gleicher Länge sind.

Nachteile:

  • Verlust von Werten, wenn die tatsächliche Länge der Sammlungen unterschiedlich ist.

Positiver Fall

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:

  • Garantierte Verarbeitung aller Elemente.
  • Es kann explizit ein "leerer" Wert festgelegt werden.

Nachteile:

  • Ein externes Modul muss importiert werden.
  • Es ist wichtig, fillvalue nicht zu vergessen, sonst ist es standardmäßig None.