Das itertools-Modul in Python: Iteratoren clever kombinieren
itertools liefert dir speichereffiziente Bausteine für Schleifen und Iteratoren. Du lernst count, cycle, chain, groupby, combinations und mehr – mit lauffähigen Beispielen.
Wenn du in Python mit Schleifen arbeitest, schreibst du oft mehr Code als nötig. Verschachtelte for-Loops, Zähler, temporäre Listen – all das lässt sich mit dem Standardmodul itertools deutlich eleganter und vor allem speichereffizienter lösen. itertools ist bereits in Python eingebaut, du musst nichts installieren. In diesem Beitrag zeige ich dir die nützlichsten Funktionen und wann du sie einsetzt.
Warum itertools?
Die Funktionen aus itertools geben fast immer einen Iterator zurück, keine Liste. Das bedeutet: Die Werte werden erst berechnet, wenn du sie brauchst (Lazy Evaluation). Bei großen Datenmengen sparst du dadurch enorm viel Arbeitsspeicher, weil nie alles gleichzeitig im RAM liegt. Ein Iterator wird mit einer normalen for-Schleife durchlaufen oder mit list() in eine Liste umgewandelt, wenn du das Ergebnis wirklich vollständig brauchst.
import itertools
# Import einmal am Anfang der Datei – das reicht für alle Beispiele
print(itertools.__doc__[:60])Endlose Iteratoren: count, cycle und repeat
Drei Funktionen erzeugen unendliche Sequenzen. Da sie nie von selbst enden, brauchst du immer eine Abbruchbedingung – etwa break oder zip() mit einer endlichen Sequenz.
import itertools
# count: zählt ab einem Startwert hoch (optional mit Schrittweite)
for i in itertools.count(start=10, step=2):
if i > 16:
break
print(i) # 10, 12, 14, 16
# cycle: wiederholt eine Sequenz endlos
farben = itertools.cycle(["rot", "gelb", "grün"])
for _ in range(5):
print(next(farben)) # rot, gelb, grün, rot, gelb
# repeat: gibt denselben Wert n-mal zurück
print(list(itertools.repeat("hi", 3))) # ['hi', 'hi', 'hi']Ein häufiger Einsatz von count ist das Nummerieren – aber dafür ist die eingebaute Funktion enumerate() meist die bessere Wahl. cycle dagegen ist praktisch, wenn du z. B. abwechselnd Zeilen einfärben oder Aufgaben reihum verteilen willst.
Sequenzen verbinden mit chain
Mit chain hängst du mehrere Iterables hintereinander, ohne sie vorher zu einer großen Liste zusammenzufügen. Das ist sauberer als liste_a + liste_b und funktioniert auch mit unterschiedlichen Typen.
import itertools
zahlen = [1, 2, 3]
buchstaben = ("a", "b")
gemischt = itertools.chain(zahlen, buchstaben, range(2))
print(list(gemischt)) # [1, 2, 3, 'a', 'b', 0, 1]
# chain.from_iterable flacht eine Liste von Listen ab
verschachtelt = [[1, 2], [3, 4], [5]]
print(list(itertools.chain.from_iterable(verschachtelt))) # [1, 2, 3, 4, 5]Daten gruppieren mit groupby
groupby fasst aufeinanderfolgende gleiche Elemente zu Gruppen zusammen. Wichtig: Es gruppiert nur benachbarte Elemente – deshalb musst du die Daten vorher nach demselben Schlüssel sortieren, sonst bekommst du mehrere kleine Gruppen statt einer großen.
import itertools
personen = [
{"name": "Anna", "stadt": "Berlin"},
{"name": "Ben", "stadt": "Berlin"},
{"name": "Cara", "stadt": "Hamburg"},
]
# Zuerst nach dem Gruppierungsschlüssel sortieren!
personen.sort(key=lambda p: p["stadt"])
for stadt, gruppe in itertools.groupby(personen, key=lambda p: p["stadt"]):
namen = [p["name"] for p in gruppe]
print(f"{stadt}: {namen}")
# Berlin: ['Anna', 'Ben']
# Hamburg: ['Cara']Kombinatorik: product, permutations und combinations
Diese drei Funktionen ersetzen tief verschachtelte Schleifen und sind Gold wert, wenn du alle möglichen Kombinationen brauchst – etwa beim Testen oder bei kleinen Optimierungsproblemen.
import itertools
# product: kartesisches Produkt (wie verschachtelte for-Loops)
for groesse, farbe in itertools.product(["S", "M"], ["blau", "rot"]):
print(groesse, farbe) # S blau / S rot / M blau / M rot
# permutations: alle Anordnungen (Reihenfolge zählt)
print(list(itertools.permutations([1, 2, 3], 2)))
# [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
# combinations: alle Auswahlen (Reihenfolge egal, keine Wiederholung)
print(list(itertools.combinations(["a", "b", "c"], 2)))
# [('a', 'b'), ('a', 'c'), ('b', 'c')]Filtern und zerschneiden: islice und takewhile
Auf einen unendlichen oder sehr großen Iterator kannst du kein [start:stop] anwenden. Dafür gibt es islice, das wie Slicing funktioniert, aber lazy bleibt. takewhile und dropwhile nehmen bzw. überspringen Elemente, solange eine Bedingung gilt.
import itertools
# islice: die ersten 5 Werte aus einem endlosen Zähler
erste_fuenf = itertools.islice(itertools.count(), 5)
print(list(erste_fuenf)) # [0, 1, 2, 3, 4]
zahlen = [1, 3, 5, 8, 9, 2]
# takewhile: nimm Elemente, solange sie ungerade sind
print(list(itertools.takewhile(lambda x: x % 2 == 1, zahlen))) # [1, 3, 5]
# dropwhile: überspringe sie, gib den Rest zurück
print(list(itertools.dropwhile(lambda x: x % 2 == 1, zahlen))) # [8, 9, 2]Fazit
itertools macht deinen Code kürzer, lesbarer und speicherschonender. Merk dir grob drei Kategorien: endlose Iteratoren (count, cycle, repeat) für generierte Sequenzen, Verbinden und Gruppieren (chain, groupby) für das Umformen von Daten und Kombinatorik (product, permutations, combinations) für alle möglichen Anordnungen. Der beste Weg, es zu verinnerlichen: Nimm dir beim nächsten verschachtelten Loop kurz Zeit und prüfe, ob eine itertools-Funktion die Arbeit übernehmen kann. Meistens gibt es eine – und dein zukünftiges Ich wird es dir danken.