Lektionen des Moduls (3/4)
Generator-Ausdrücke
Eine Generator Expression (Generatorausdruck) ähnelt einer List Comprehension, verwendet jedoch runde Klammern anstelle von eckigen Klammern. Der Unterschied ist enorm: Sie baut keine Liste im Speicher auf, sondern erzeugt Elemente bei Bedarf (on-demand), einzeln nacheinander.
gen = (n * n for n in range(1_000_000))
# sofort, konstanter Speicher: noch keine Berechnung durchgeführt
list_comp = [n * n for n in range(1_000_000)]
# belegt Speicher für 1 Mio. GanzzahlenLaziness (Verzögerte Auswertung)
Der Generator tut nichts, bis jemand nach dem nächsten Wert fragt:
gen = (n * n for n in range(5))
next(gen) # 0 (jetzt berechnet)
next(gen) # 1
next(gen) # 4
# ... und so weiter, bis StopIterationEr erschöpft sich: Nach dem Konsumieren aller Elemente ist er für immer leer. Um ihn wiederzuverwenden, musst du ihn neu erstellen.
Wann man Generator Expressions verwendet
Wenn du die Ergebnisse an eine Funktion übergibst, die sie nacheinander konsumiert:
total = sum(n * n for n in range(1_000_000))
# keine Zwischenliste, konstanter Speichersum, any, all, max, min, "".join(...) akzeptieren alle Generatoren.
Wenn die äußere Funktion nur die Aufrufklammern benötigt, kannst du
die eigenen Klammern des Generators weglassen:
sum((n * n for n in range(10))) # OK
sum(n * n for n in range(10)) # IDENTISCH, lesbarerany und all: Kurzschlussauswertung (Short-circuit)
any(...) und all(...) stoppen die Iteration, sobald sie die Antwort kennen.
Mit einem Generator werden die nachfolgenden Elemente gar nicht erst berechnet.
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums) # True (stoppt bei 4)
all(n > 0 for n in nums) # True
all(n > 2 for n in nums) # False (stoppt bei 1)Muster: Lazy Pipeline
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
prime_dieci.append(r)
if len(prime_dieci) == 10:
breakKeine Zwischenlisten, selbst bei riesigen Eingaben.
Konsumieren von Generatoren mit sum, any, all
Generator Expressions eignen sich hervorragend für die direkte Übergabe an Funktionen, die Iterables konsumieren, wie sum(), any() oder all(). In diesem Fall kannst du die äußeren Klammern der Generator Expression weglassen und einfach schreiben:
squares_sum = sum(x**2 for x in range(10))Dies hält deinen Code sauber und äußerst speichereffizient.
Probiere es aus
Berechne die Summe der Quadrate der Zahlen von 1 bis einschließlich 100 mithilfe eines Generatorausdrucks innerhalb von sum(). Weise das Ergebnis `tot` zu. Evaluiere `tot`.
Hinweis anzeigen
range(1, 101) schließt 100 ein.
Lösung nach 3 Versuchen verfügbar
Wiederholungsübung
Gegeben sei `words = ['ciao', 'mondo', 'PYTHON', 'java']`. Verwende any() mit einer Generator Expression, um zu prüfen, ob MINDESTENS ein Wort komplett in Großbuchstaben geschrieben ist (.isupper()). Weise das Ergebnis `has_uppercase` zu. Evaluiere `has_uppercase`.
Hinweis anzeigen
any(p.isupper() for p in words)
Lösung nach 3 Versuchen verfügbar
Zusätzliche Herausforderung
Verwende einen Generatorausdruck, der direkt an die Funktion `sum()` übergeben wird, um die Summe der Quadrate aller Ganzzahlen von 1 bis einschließlich 100 zu berechnen. Speichere das Ergebnis in `total_sum` und evaluiere es.
Hinweis anzeigen
Schreibe total_sum = sum(x**2 for x in range(1, 101)). Doppelte Klammern sind nicht erforderlich.
Lösung nach 3 Versuchen verfügbar