EMZETT.
Login

Kurz: Hinter jeder for-Schleife steckt ein Iterator: ein Objekt, das Element für Element herausgibt. Mit Generatoren schreibst du solche Objekte besonders einfach, und zwar mit dem Schlüsselwort yield.

Teil des Kurses Python

Kapitel 26 von 44 im Kurs Python. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Hinter jeder for-Schleife steckt ein Iterator: ein Objekt, das Element für Element herausgibt. Mit Generatoren schreibst du solche Objekte besonders einfach, und zwar mit dem Schlüsselwort yield.

Wie for wirklich funktioniert

Listen, Texte, Dictionaries und andere Sammlungen sind iterierbar. Mit iter() bekommst du einen Iterator, mit next() das jeweils nächste Element. Ist nichts mehr da, entsteht StopIteration:

it = iter(["a", "b", "c"])
print(next(it))
print(next(it))
print(next(it))
print(next(it, "Ende"))     # mit Standardwert statt Fehler

Ausgabe:

a
b
c
Ende

Eine Funktion mit yield

Eine Funktion mit yield heißt Generatorfunktion. Beim Aufruf läuft sie nicht sofort los, sondern liefert einen Generator. Bei jedem next() läuft sie bis zum nächsten yield und pausiert dort:

def zaehle_bis(n):
    i = 1
    while i <= n:
        yield i
        i += 1
 
for zahl in zaehle_bis(4):
    print(zahl)
 
gen = zaehle_bis(2)
print(next(gen), next(gen))

Ausgabe:

1
2
3
4
1 2

Der Vorteil: Die Werte entstehen erst, wenn sie gebraucht werden. Ein Generator braucht fast keinen Speicher, auch wenn er Millionen Werte liefert.

Beispiel: Fibonacci-Zahlen

def fibonacci():
    a, b = 0, 1
    while True:            # unendlich! – aber nur bei Bedarf berechnet
        yield a
        a, b = b, a + b
 
from itertools import islice
print(list(islice(fibonacci(), 10)))

Ausgabe:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

itertools.islice nimmt die ersten Elemente eines (auch unendlichen) Iterators.

Generator-Ausdrücke

Mit runden Klammern statt eckigen entsteht ein Generator ohne eigene Funktion:

quadrate = (x * x for x in range(1, 6))
print(next(quadrate))
print(sum(quadrate))       # summiert die restlichen vier

Ausgabe:

1
54

Ein Generator kann man nur einmal durchlaufen:

g = (x for x in [1, 2, 3])
print(list(g))
print(list(g))

Ausgabe:

[1, 2, 3]
[]

Eigene Iteratoren

Eine Klasse wird zum Iterator, wenn sie __iter__ und __next__ besitzt. In den meisten Fällen ist ein Generator aber die einfachere Lösung:

class Countdown:
    def __init__(self, start):
        self.start = start
 
    def __iter__(self):
        n = self.start
        while n > 0:
            yield n
            n -= 1
 
print(list(Countdown(3)))

Ausgabe:

[3, 2, 1]

Nützliche Werkzeuge aus itertools

FunktionWirkung
count(start)unendlich zählen
cycle(seq)Folge endlos wiederholen
islice(it, n)die ersten n Elemente
chain(a, b)mehrere Folgen hintereinander
product(a, b)alle Kombinationen (kartesisches Produkt)
permutations(seq)alle Anordnungen
combinations(seq, k)alle Auswahlen ohne Reihenfolge
from itertools import chain, combinations, product
print(list(chain([1, 2], "ab")))
print(list(combinations("ABC", 2)))
print(list(product([0, 1], repeat=2)))

Ausgabe:

[1, 2, 'a', 'b']
[('A', 'B'), ('A', 'C'), ('B', 'C')]
[(0, 0), (0, 1), (1, 0), (1, 1)]

Merke

  • Ein Iterator liefert mit next() Element für Element; StopIteration bedeutet “fertig”
  • yield macht aus einer Funktion einen Generator, der zwischen den Werten pausiert
  • Generatoren sparen Speicher und können unendlich sein
  • Generator-Ausdruck: (ausdruck for x in folge)
  • Ein Generator lässt sich nur einmal durchlaufen
  • itertools bringt viele fertige Bausteine

Übungsaufgabe

Schreibe einen Generator gerade_zahlen(grenze), der alle geraden Zahlen bis zur Grenze liefert, und gib seine Werte mit einer Schleife aus.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Rekursion

Weiter: Dekoratoren

Alle Kapitel: Python im Überblick