Meistere das Iterationsprotokoll und Generatoren, um Datenströme lazy und bei konstantem Speicher zu verarbeiten.
Diese Lektion in Kodokon öffnenPythons for ist nichts weiter als ein Protokoll: iter(obj) fordert einen Iterator an, dann wird next() aufgerufen, bis zur Ausnahme StopIteration. Unterscheide unbedingt das Iterable (die Liste, die bei jedem Durchgang einen frischen Iterator ausgeben kann) vom Iterator (dem Cursor, der nur einmal durchlaufen werden kann). Dieses Protokoll zu verstehen heißt zu verstehen, warum manche Objekte "aufgebraucht werden".
numbers = [10, 20, 30]
iterator = iter(numbers)
print(next(iterator))
print(next(iterator))
print(next(iterator))
# next(iterator) would raise StopIterationEine Funktion, die yield enthält, läuft beim Aufruf nicht: Sie gibt einen Generator zurück, einen Iterator, dessen Rumpf auf Anforderung läuft. Jedes next() rückt bis zum nächsten yield vor, wo die Ausführung samt ihres gesamten lokalen Zustands angehalten wird. Die unmittelbare Folge: Der Speicher bleibt konstant, egal wie groß der Strom ist - du produzierst die Werte einen nach dem anderen, statt eine vollständige Liste zu materialisieren.
def squares(limit):
n = 0
while n < limit:
yield n * n
n += 1
gen = squares(4)
print(next(gen)) # 0
print(list(gen)) # [1, 4, 9]Der Hauptnutzen im Produktivbetrieb: Pipelines. Jede Stufe konsumiert den Strom der vorherigen und produziert lazy ihren eigenen; nichts läuft vor der finalen Konsumierung (list(), sum(), ein for). Ein Kompromiss, den du im Kopf behalten solltest: Eine Liste kann mehrfach durchlaufen und geschnitten werden, ein Generator nicht; dafür verarbeitet ein Generator eine 10-GB-Datei, ohne den RAM zu sättigen. Generator-Ausdrücke - (f(x) for x in xs if cond) - decken die einfachen Stufen ab, ohne eine Funktion zu definieren.
lines = [" 12 ", "x", " 7", "", "30"]
def clean(rows):
for row in rows:
row = row.strip()
if row.isdigit():
yield int(row)
def keep_from(values, floor):
return (v for v in values if v >= floor)
pipeline = keep_from(clean(lines), 10)
print(list(pipeline)) # [12, 30]