Iteratoren und Generatoren sind die Grundlage für die effektive Verarbeitung von Sequenzen in Python. Historisch gesehen strebte Python danach, die Arbeit mit Datenströmen zu erleichtern und überflüssige Speicherung großer Sammlungen im Speicher zu vermeiden. Zuerst wurde die Unterstützung für Iteratoren durch die Protokolle __iter__ und __next__ eingeführt, danach kamen Generatoren, die es ermöglichen, einfache Iteratoren mit Konstruktionen auf Basis von yield zu erstellen.
Problem: Oft müssen große Datenmengen verarbeitet werden (z.B. Streaming von Dateien oder Datenbanken), was nicht bequem und effizient möglich ist, wenn alles auf einmal in den Speicher geladen wird. Gewöhnliche Funktionen geben alle Ergebnisse gleichzeitig zurück, und die Erstellung eigener Iteratoren durch Klassen ist oft zu umständlich für einfache Fälle.
Lösung: Der yield-Mechanismus ermöglicht eine "faule" Datenproduktion. Eine Generatorfunktion gibt keine Liste oder andere Sammlung zurück, sondern ein Generatorobjekt — einen Iterator, der Werte nach Bedarf berechnet.
Beispielcode:
# Ein einfacher Generator def countdown(n): while n > 0: yield n n -= 1 for i in countdown(3): print(i) # 3, 2, 1
Hauptmerkmale:
Kann man return und yield in einer Funktion verwenden?
Ja, aber return in einem Generator beendet die Iteration (wirft StopIteration), während yield beliebig oft verwendet werden kann.
def example(): yield 1 return # StopIteration
Warum kann man einen Generator nach Abschluss nicht "neustarten"?
Ein Generator kann nach Abschluss der Iterationen (StopIteration) nicht neu gestartet werden, er muss neu erstellt werden.
gen = countdown(2) list(gen) # [2, 1] list(gen) # [] (Generator ist bereits erschöpft)
Was ist der Unterschied zwischen einem Generator und einem Iterator?
Ein Generator ist ein Spezialfall eines Iterators; jedes Objekt mit den Methoden iter und next ist ein Iterator, aber ein Generator wird durch eine Funktion mit yield erstellt.
Ein Entwickler schrieb eine Funktion, die eine Million Zeilen einer Datei in den Speicher über list(fd) lädt, um sie zu analysieren. Dies führte zu einem Speicherüberlauf auf dem Server.
Vorteile:
Nachteile:
Verwendung eines Generators zum zeilenweisen Lesen einer Datei (eine Zeile nach der anderen) und Analyse der Daten im Fluss mithilfe von yield.
Vorteile:
Nachteile: