Python itertools: Vollständiger Leitfaden zu Iterator-Bausteinen
Updated on
Schleifen zu schreiben ist für jeden Python-Entwickler selbstverständlich. Doch bei genauerer Betrachtung der meisten Codebasen finden sich immer wieder dieselben Muster: Verschachtelte Listen abflachen, Kombinationen erzeugen, sortierte Daten gruppieren, Iteratoren aufteilen, laufende Summen berechnen. Jedes dieser Muster wird typischerweise mit einer handgeschriebenen for-Schleife, temporären Variablen und Index-Jonglage gelöst. Der Code funktioniert, ist aber umständlich, fehleranfällig und langsam bei wachsenden Datensätzen.
Diese Probleme verstärken sich gegenseitig. Eine verschachtelte Schleife über zwei Listen erzeugt ein kartesisches Produkt, aber die manuelle Implementierung verschleiert die Absicht. Alle 3er-Kombinationen aus einer Sammlung zu erzeugen erfordert sorgfältige Indexverwaltung. Aufeinanderfolgende Elemente nach einem Schlüssel zu gruppieren benötigt eine Zustandsvariable, bei der leicht Fehler passieren. Jedes dieser Muster wurde bereits in Pythons itertools-Modul gelöst, getestet und optimiert -- einem Standardbibliothek-Toolkit, das mehrzeilige Schleifenkonstrukte in einzelne, lesbare Funktionsaufrufe verwandelt, die speichereffiziente Iteratoren erzeugen.
Dieser Leitfaden behandelt jede wichtige Funktion in itertools mit praktischen, ausführbaren Beispielen. Am Ende haben Sie eine Referenz, um umständliche Schleifenmuster durch saubere, performante Iterator-Pipelines zu ersetzen.
itertools importieren
Das itertools-Modul ist Teil von Pythons Standardbibliothek. Es ist keine Installation erforderlich.
import itertools
# Oder bestimmte Funktionen importieren
from itertools import chain, combinations, groupby, isliceUnendliche Iteratoren
Diese Funktionen erzeugen Iteratoren, die von selbst nie terminieren. Sie müssen islice(), takewhile() oder einen anderen Stoppmechanismus verwenden, um Endlosschleifen zu vermeiden.
count() -- Arithmetische Folgen
count(start, step) erzeugt gleichmäßig verteilte Werte ab start, mit Schrittweite step (Standard 1).
from itertools import count, islice
# Zählen ab 10, Schrittweite 2
counter = count(10, 2)
print(list(islice(counter, 6)))
# [10, 12, 14, 16, 18, 20]
# Gleitkomma-Folgen
floats = count(0.0, 0.25)
print(list(islice(floats, 5)))
# [0.0, 0.25, 0.5, 0.75, 1.0]
# Zeilen mit Index beschriften
names = ["Alice", "Bob", "Charlie"]
for idx, name in zip(count(1), names):
print(f"{idx}. {name}")
# 1. Alice
# 2. Bob
# 3. Charliecycle() -- Eine Sequenz endlos wiederholen
cycle(iterable) speichert eine Kopie des Iterables und gibt Elemente daraus wiederholt aus.
from itertools import cycle, islice
colors = cycle(["red", "green", "blue"])
print(list(islice(colors, 7)))
# ['red', 'green', 'blue', 'red', 'green', 'blue', 'red']
# Round-Robin-Zuweisung
tasks = ["task_a", "task_b", "task_c", "task_d", "task_e"]
workers = cycle(["Worker1", "Worker2", "Worker3"])
assignments = {task: worker for task, worker in zip(tasks, workers)}
print(assignments)
# {'task_a': 'Worker1', 'task_b': 'Worker2', 'task_c': 'Worker3',
# 'task_d': 'Worker1', 'task_e': 'Worker2'}repeat() -- Denselben Wert ausgeben
repeat(value, times) gibt value entweder unendlich oder eine bestimmte Anzahl von Malen aus.
from itertools import repeat
# Feste Wiederholungen
print(list(repeat("hello", 3)))
# ['hello', 'hello', 'hello']
# repeat als konstantes Argument in map() verwenden
import operator
bases = [2, 3, 4, 5]
squared = list(map(operator.pow, bases, repeat(2)))
print(squared)
# [4, 9, 16, 25]Endliche Iteratoren: Aufteilen und Filtern
Diese Funktionen verarbeiten ein oder mehrere Eingabe-Iterables und erzeugen eine endliche Ausgabe.
chain() -- Mehrere Iterables verketten
chain(*iterables) gibt Elemente aus dem ersten Iterable aus, bis es erschöpft ist, dann aus dem nächsten, und so weiter. chain.from_iterable() akzeptiert ein einzelnes Iterable von Iterables.
from itertools import chain
# Mehrere Listen verketten
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
print(list(chain(a, b, c)))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Eine Verschachtelungsebene abflachen
nested = [[1, 2], [3, 4], [5, 6]]
print(list(chain.from_iterable(nested)))
# [1, 2, 3, 4, 5, 6]
# Generator mit einer Liste kombinieren
def evens():
yield 2; yield 4; yield 6
print(list(chain(evens(), [8, 10])))
# [2, 4, 6, 8, 10]compress() -- Nach Selektoren filtern
compress(data, selectors) gibt Elemente aus data zurück, bei denen das entsprechende Element in selectors wahr ist.
from itertools import compress
data = ["A", "B", "C", "D", "E"]
selectors = [1, 0, 1, 0, 1]
print(list(compress(data, selectors)))
# ['A', 'C', 'E']
# Mit booleschen Bedingungen
values = [10, 25, 3, 42, 7, 18]
mask = [v > 15 for v in values]
print(list(compress(values, mask)))
# [25, 42, 18]islice() -- Jeden Iterator aufteilen
islice(iterable, stop) oder islice(iterable, start, stop, step) funktioniert wie Slice-Notation, aber mit jedem Iterator, ohne zuerst eine Liste aufzubauen.
from itertools import islice, count
# Erste 5 Elemente eines unendlichen Zählers
print(list(islice(count(100), 5)))
# [100, 101, 102, 103, 104]
# Elemente 3 bis 8
print(list(islice(range(20), 3, 9)))
# [3, 4, 5, 6, 7, 8]
# Jedes 3. Element der ersten 15
print(list(islice(range(100), 0, 15, 3)))
# [0, 3, 6, 9, 12]
# Erste 5 Zeilen aus einem Datei-Iterator lesen
# lines = list(islice(open("data.txt"), 5))takewhile() und dropwhile() -- Bedingtes Aufteilen
takewhile(predicate, iterable) gibt Elemente aus, solange das Prädikat wahr ist, dann stoppt es. dropwhile(predicate, iterable) überspringt Elemente, solange das Prädikat wahr ist, und gibt dann den Rest aus.
from itertools import takewhile, dropwhile
data = [1, 3, 5, 7, 2, 4, 6, 8]
# Elemente nehmen, solange sie kleiner als 6 sind
print(list(takewhile(lambda x: x < 6, data)))
# [1, 3, 5]
# Elemente verwerfen, solange sie kleiner als 6 sind
print(list(dropwhile(lambda x: x < 6, data)))
# [7, 2, 4, 6, 8]Beachten Sie, dass takewhile beim ersten False-Wert stoppt; es wird nicht fortgesetzt, wenn spätere Elemente das Prädikat wieder erfüllen.
starmap() -- Funktion auf vorgruppierte Argumente anwenden
starmap(function, iterable) wendet eine Funktion mit Argument-Tupeln aus dem Iterable an. Dies entspricht function(*args) für jedes args im Iterable.
from itertools import starmap
import operator
pairs = [(2, 5), (3, 4), (10, 3)]
print(list(starmap(operator.mul, pairs)))
# [10, 12, 30]
# Hypotenuse für mehrere Dreiecke berechnen
import math
triangles = [(3, 4), (5, 12), (8, 15)]
print(list(starmap(math.hypot, triangles)))
# [5.0, 13.0, 17.0]filterfalse() -- Inverser Filter
filterfalse(predicate, iterable) gibt Elemente aus, für die das Prädikat False zurückgibt. Es ist das Komplement der eingebauten Funktion filter().
from itertools import filterfalse
numbers = range(10)
# Ungerade Zahlen behalten (wo "is_even" falsch ist)
odd = list(filterfalse(lambda x: x % 2 == 0, numbers))
print(odd)
# [1, 3, 5, 7, 9]Kombinatorische Iteratoren
Diese Funktionen erzeugen alle möglichen Anordnungen von Eingabeelementen. Sie sind zentral für Brute-Force-Suche, Tests und mathematische Berechnungen.
product() -- Kartesisches Produkt
itertools.product(*iterables, repeat=1) ersetzt verschachtelte for-Schleifen über mehrere Sequenzen.
from itertools import product
# Zwei Listen
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
print(list(product(colors, sizes)))
# [('red', 'S'), ('red', 'M'), ('red', 'L'),
# ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]
# Äquivalent zu:
# [(c, s) for c in colors for s in sizes]
# Würfelwürfe: zwei sechsseitige Würfel
dice = range(1, 7)
all_rolls = list(product(dice, repeat=2))
print(f"Gesamtkombinationen: {len(all_rolls)}")
# Gesamtkombinationen: 36
print(all_rolls[:5])
# [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5)]permutations() -- Alle Anordnungen
permutations(iterable, r) erzeugt alle möglichen Anordnungen der Länge r aus der Eingabe. Die Reihenfolge ist wichtig, daher werden sowohl (A, B) als auch (B, A) eingeschlossen.
from itertools import permutations
# Alle 2-Buchstaben-Anordnungen aus 'ABC'
print(list(permutations("ABC", 2)))
# [('A', 'B'), ('A', 'C'), ('B', 'A'),
# ('B', 'C'), ('C', 'A'), ('C', 'B')]
# Vollständige Permutationen (alle Elemente)
print(list(permutations([1, 2, 3])))
# [(1, 2, 3), (1, 3, 2), (2, 1, 3),
# (2, 3, 1), (3, 1, 2), (3, 2, 1)]
# Anzahl der Permutationen: n! / (n-r)!
import math
n, r = 5, 3
print(f"P({n},{r}) = {math.perm(n, r)}")
# P(5,3) = 60combinations() -- Eindeutige Teilmengen
combinations(iterable, r) erzeugt alle eindeutigen Teilmengen der Länge r. Die Reihenfolge spielt keine Rolle, daher wird (A, B) eingeschlossen, aber (B, A) nicht.
from itertools import combinations
# Alle 2-Element-Kombinationen aus [1, 2, 3, 4]
print(list(combinations([1, 2, 3, 4], 2)))
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
# 3 Beläge aus einer Speisekarte wählen
toppings = ["cheese", "pepperoni", "mushrooms", "onions", "peppers"]
combos = list(combinations(toppings, 3))
print(f"Anzahl der 3-Belag-Kombinationen: {len(combos)}")
# Anzahl der 3-Belag-Kombinationen: 10
for c in combos[:3]:
print(c)
# ('cheese', 'pepperoni', 'mushrooms')
# ('cheese', 'pepperoni', 'onions')
# ('cheese', 'pepperoni', 'peppers')combinations_with_replacement() -- Teilmengen mit Wiederholung
Elemente können mehrfach ausgewählt werden.
from itertools import combinations_with_replacement
# Münznominale: 3 Münzen wählen
coins = [1, 5, 10, 25]
selections = list(combinations_with_replacement(coins, 3))
print(f"Gesamtauswahlen: {len(selections)}")
# Gesamtauswahlen: 35
print(selections[:5])
# [(1, 1, 1), (1, 1, 5), (1, 1, 10), (1, 1, 25), (1, 5, 5)]Daten gruppieren mit groupby()
itertools.groupby(iterable, key=None) gruppiert aufeinanderfolgende Elemente, die denselben Schlüssel haben. Die Eingabe muss zuerst nach dem Schlüssel sortiert sein, da identische Schlüssel an nicht benachbarten Positionen sonst separate Gruppen bilden.
from itertools import groupby
# Aufeinanderfolgende gleiche Elemente gruppieren
data = "AAABBBCCAAB"
for key, group in groupby(data):
print(f"{key}: {list(group)}")
# A: ['A', 'A', 'A']
# B: ['B', 'B', 'B']
# C: ['C', 'C']
# A: ['A', 'A']
# B: ['B']Praktisches Beispiel: Datensätze nach Kategorie gruppieren
from itertools import groupby
from operator import itemgetter
sales = [
{"product": "Widget", "category": "Hardware", "revenue": 150},
{"product": "Gadget", "category": "Hardware", "revenue": 300},
{"product": "App Pro", "category": "Software", "revenue": 500},
{"product": "Cloud X", "category": "Software", "revenue": 200},
{"product": "Cable", "category": "Hardware", "revenue": 50},
]
# Zuerst nach Kategorie sortieren -- groupby erfordert sortierte Eingabe
sales.sort(key=itemgetter("category"))
for category, items in groupby(sales, key=itemgetter("category")):
item_list = list(items)
total = sum(item["revenue"] for item in item_list)
print(f"{category}: {len(item_list)} Produkte, ${total} Umsatz")
# Hardware: 3 Produkte, $500 Umsatz
# Software: 2 Produkte, $700 UmsatzZahlen nach Eigenschaft gruppieren
from itertools import groupby
numbers = sorted(range(1, 16), key=lambda x: x % 3)
for remainder, group in groupby(numbers, key=lambda x: x % 3):
print(f"Rest {remainder}: {list(group)}")
# Rest 0: [3, 6, 9, 12, 15]
# Rest 1: [1, 4, 7, 10, 13]
# Rest 2: [2, 5, 8, 11, 14]Laufende Summen mit accumulate()
itertools.accumulate(iterable, func=operator.add, initial=None) erzeugt laufende (kumulative) Ergebnisse. Standardmäßig berechnet es eine laufende Summe, aber jede binäre Funktion kann übergeben werden.
from itertools import accumulate
import operator
# Laufende Summe
data = [1, 2, 3, 4, 5]
print(list(accumulate(data)))
# [1, 3, 6, 10, 15]
# Laufendes Produkt
print(list(accumulate(data, operator.mul)))
# [1, 2, 6, 24, 120]
# Laufendes Maximum
temps = [72, 68, 75, 71, 78, 74, 80]
print(list(accumulate(temps, max)))
# [72, 72, 75, 75, 78, 78, 80]
# Mit einem Anfangswert
print(list(accumulate(data, operator.add, initial=100)))
# [100, 101, 103, 106, 110, 115]Praktisch: Laufender Kontostand
from itertools import accumulate
transactions = [1000, -200, -150, 500, -300, -100, 250]
balances = list(accumulate(transactions))
print("Transaktionen:", transactions)
print("Kontostände: ", balances)
# Transaktionen: [1000, -200, -150, 500, -300, -100, 250]
# Kontostände: [1000, 800, 650, 1150, 850, 750, 1000]Vollständige Funktionsreferenz
| Funktion | Kategorie | Beschreibung | Beispielausgabe |
|---|---|---|---|
count(start, step) | Unendlich | Arithmetische Folge | 10, 12, 14, 16, ... |
cycle(iterable) | Unendlich | Wiederholt Iterable endlos | A, B, C, A, B, C, ... |
repeat(val, n) | Unendlich | Gleicher Wert n-mal (oder endlos) | 5, 5, 5, 5 |
chain(*iterables) | Endlich | Iterables verketten | [1,2] + [3,4] -> 1,2,3,4 |
compress(data, sel) | Endlich | Nach booleschen Selektoren filtern | ABCDE, 10101 -> A,C,E |
islice(iter, start, stop, step) | Endlich | Jeden Iterator aufteilen | Wie list[start:stop:step] |
takewhile(pred, iter) | Endlich | Ausgabe solange Prädikat wahr | Stoppt bei erstem False |
dropwhile(pred, iter) | Endlich | Überspringen solange Prädikat wahr | Startet bei erstem False |
filterfalse(pred, iter) | Endlich | Ausgabe wo Prädikat falsch | Umkehrung von filter() |
starmap(func, iter) | Endlich | Funktion auf Argument-Tupel anwenden | func(*args) für jedes |
accumulate(iter, func) | Endlich | Laufende Summen | [1,3,6,10,15] |
groupby(iter, key) | Endlich | Aufeinanderfolgende nach Schlüssel gruppieren | Erfordert sortierte Eingabe |
product(*iters) | Kombinatorisch | Kartesisches Produkt | Ersetzt verschachtelte Schleifen |
permutations(iter, r) | Kombinatorisch | Alle r-langen Anordnungen | Reihenfolge wichtig |
combinations(iter, r) | Kombinatorisch | Alle r-langen Teilmengen | Reihenfolge unwichtig |
combinations_with_replacement(iter, r) | Kombinatorisch | Teilmengen mit Wiederholung | Elemente können sich wiederholen |
Leistung: itertools vs Manuelle Schleifen
Die itertools-Funktionen sind in C implementiert, was sie deutlich schneller und speichereffizienter macht als äquivalente Python-Schleifen. Sie erzeugen Iteratoren (Lazy Evaluation), was bedeutet, dass sie ein Element nach dem anderen ausgeben, anstatt ganze Listen im Speicher aufzubauen.
import time
from itertools import chain
# Benchmark: Eine Liste von 1000 Unterlisten mit je 1000 Elementen abflachen
nested = [list(range(1000)) for _ in range(1000)]
# Manueller Ansatz
start = time.perf_counter()
result_manual = []
for sublist in nested:
result_manual.extend(sublist)
manual_time = time.perf_counter() - start
# itertools-Ansatz
start = time.perf_counter()
result_itertools = list(chain.from_iterable(nested))
itertools_time = time.perf_counter() - start
print(f"Manuelles extend: {manual_time:.4f}s")
print(f"chain.from_iterable: {itertools_time:.4f}s")
print(f"Beschleunigung: {manual_time / itertools_time:.2f}x")
# Typische Ausgabe:
# Manuelles extend: 0.0180s
# chain.from_iterable: 0.0120s
# Beschleunigung: 1.50xSpeichereffizienz
import sys
from itertools import islice, count
# Eine Liste mit 1 Million Ganzzahlen
big_list = list(range(1_000_000))
print(f"Listen-Speicher: {sys.getsizeof(big_list):,} Bytes")
# Listen-Speicher: 8,000,056 Bytes
# Ein Iterator über denselben Bereich (vernachlässigbarer Speicher)
big_iter = islice(count(), 1_000_000)
print(f"Iterator-Speicher: {sys.getsizeof(big_iter)} Bytes")
# Iterator-Speicher: 72 BytesIteratoren verarbeiten ein Element nach dem anderen. Beim Verketten mehrerer Transformationen werden keine Zwischenlisten erstellt.
Gängige Rezepte
Die itertools-Dokumentation enthält mehrere "Rezepte" -- gängige Muster, die aus den Grundbausteinen des Moduls aufgebaut sind. Hier sind die nützlichsten.
Verschachtelte Listen abflachen
from itertools import chain
def flatten(nested_list):
"""Eine Verschachtelungsebene abflachen."""
return list(chain.from_iterable(nested_list))
data = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
print(flatten(data))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]Gleitendes Fenster
from itertools import islice
from collections import deque
def sliding_window(iterable, n):
"""Ein gleitendes Fenster der Größe n über das Iterable zurückgeben."""
iterator = iter(iterable)
window = deque(islice(iterator, n), maxlen=n)
if len(window) == n:
yield tuple(window)
for item in iterator:
window.append(item)
yield tuple(window)
data = [1, 2, 3, 4, 5, 6, 7]
for window in sliding_window(data, 3):
print(window)
# (1, 2, 3)
# (2, 3, 4)
# (3, 4, 5)
# (4, 5, 6)
# (5, 6, 7)Hinweis: Python 3.12+ enthält itertools.pairwise() für Fenstergröße 2 und itertools.batched() für nicht-überlappende Blöcke.
Ein Iterable in Blöcke aufteilen
from itertools import islice
def chunked(iterable, size):
"""Ein Iterable in Blöcke fester Größe aufteilen."""
iterator = iter(iterable)
while True:
chunk = list(islice(iterator, size))
if not chunk:
break
yield chunk
data = list(range(1, 12))
for chunk in chunked(data, 3):
print(chunk)
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
# [10, 11]In Python 3.12+ können Sie itertools.batched(iterable, n) für dasselbe Ergebnis mit einer eingebauten Funktion verwenden.
Paarweise Iteration
from itertools import pairwise # Python 3.10+
data = [10, 20, 30, 40, 50]
for a, b in pairwise(data):
print(f"{a} -> {b}, Differenz = {b - a}")
# 10 -> 20, Differenz = 10
# 20 -> 30, Differenz = 10
# 30 -> 40, Differenz = 10
# 40 -> 50, Differenz = 10Round-Robin aus mehreren Iterables
from itertools import cycle, islice
def roundrobin(*iterables):
"""Elemente abwechselnd aus jedem Iterable ausgeben."""
iterators = [iter(it) for it in iterables]
active = len(iterators)
nexts = cycle(iter(it).__next__ for it in iterables)
# Einfacherer Ansatz:
pending = len(iterables)
iters = cycle(iter(it) for it in iterables)
# Rezept aus der Dokumentation verwenden:
result = []
iterators = list(map(iter, iterables))
while iterators:
next_iterators = []
for it in iterators:
try:
result.append(next(it))
next_iterators.append(it)
except StopIteration:
pass
iterators = next_iterators
return result
print(roundrobin("ABC", "D", "EF"))
# ['A', 'D', 'E', 'B', 'F', 'C']Eindeutige Elemente unter Beibehaltung der Reihenfolge
from itertools import filterfalse
def unique_everseen(iterable):
"""Eindeutige Elemente ausgeben, Reihenfolge des ersten Auftretens beibehalten."""
seen = set()
for element in filterfalse(seen.__contains__, iterable):
seen.add(element)
yield element
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(list(unique_everseen(data)))
# [3, 1, 4, 5, 9, 2, 6]itertools-Funktionen verketten
Die wahre Stärke von itertools zeigt sich, wenn Sie mehrere Funktionen zu einer Pipeline zusammensetzen. Da jede Funktion einen Iterator zurückgibt, wird kein Speicher zwischen den Stufen verschwendet.
from itertools import chain, compress, accumulate, islice
# Pipeline: abflachen -> filtern -> laufende Summe -> erste 5 nehmen
nested = [[10, 20, 30], [5, 15, 25], [40, 50]]
mask = [True, False, True, True, False, True, True, False]
flat = chain.from_iterable(nested) # 10, 20, 30, 5, 15, 25, 40, 50
filtered = compress(flat, mask) # 10, 30, 5, 25, 40
running = accumulate(filtered) # 10, 40, 45, 70, 110
first_four = list(islice(running, 4))
print(first_four)
# [10, 40, 45, 70]In keinem Schritt wurde eine Zwischenliste erstellt. Jeder Wert fließt einzeln durch die Pipeline.
Mit itertools in Jupyter experimentieren
Iterator-Pipelines können schwierig zu debuggen sein, da Iteratoren beim ersten Durchlauf verbraucht werden. Eine interaktive Notebook-Umgebung macht es einfach, Zwischenergebnisse zu inspizieren, Randfälle zu testen und zu visualisieren, wie Daten durch jede Stufe fließen. RunCell (opens in a new tab) bietet eine KI-gestützte Jupyter-Umgebung, die für diese Art der Exploration gut geeignet ist -- Sie können Iterator-Ausgaben schrittweise durchgehen, KI-gestützte Erklärungen erhalten, wenn sich eine Pipeline unerwartet verhält, und Rezepte schnell prototypen, bevor Sie sie in Produktionscode überführen.
FAQ
Was ist itertools in Python?
itertools ist ein Standardbibliothek-Modul, das eine Sammlung schneller, speichereffizienter Funktionen zur Erstellung und Arbeit mit Iteratoren bereitstellt. Es enthält Werkzeuge für unendliche Folgen (count, cycle, repeat), endliche Iterationsmuster (chain, islice, groupby) und Kombinatorik (product, permutations, combinations). Alle Funktionen geben Iteratoren zurück, was bedeutet, dass sie Werte faul erzeugen, ohne ganze Listen im Speicher aufzubauen.
Was ist der Unterschied zwischen itertools.combinations und itertools.permutations?
combinations(iterable, r) erzeugt alle eindeutigen Teilmengen der Länge r, bei denen die Reihenfolge keine Rolle spielt -- (A, B) und (B, A) gelten als identisch und nur (A, B) wird zurückgegeben. permutations(iterable, r) erzeugt alle Anordnungen der Länge r, bei denen die Reihenfolge wichtig ist -- sowohl (A, B) als auch (B, A) werden zurückgegeben. Für n Elemente bei der Auswahl von r erzeugt combinations n! / (r!(n-r)!) Ergebnisse, während permutations n! / (n-r)! Ergebnisse erzeugt.
Wie flache ich eine verschachtelte Liste mit itertools ab?
Verwenden Sie itertools.chain.from_iterable(), um eine Verschachtelungsebene abzuflachen. Zum Beispiel gibt list(chain.from_iterable([[1,2],[3,4],[5,6]])) [1, 2, 3, 4, 5, 6] zurück. Für tief verschachtelte Strukturen benötigen Sie einen rekursiven Ansatz, da chain.from_iterable nur eine Ebene entfernt.
Warum erfordert itertools.groupby sortierte Eingabe?
groupby() gruppiert aufeinanderfolgende Elemente, die denselben Schlüssel haben. Es durchsucht nicht das gesamte Iterable, um alle passenden Elemente zu finden. Wenn Ihre Daten [A, A, B, A] haben, erzeugt groupby drei Gruppen: A, B, A. Um eine einzelne Gruppe für jeden Schlüssel zu erhalten, sortieren Sie die Daten nach der Schlüsselfunktion, bevor Sie sie an groupby übergeben.
Ist itertools schneller als normale Python-Schleifen?
Ja. Die itertools-Funktionen sind in C als Teil der CPython-Standardbibliothek implementiert, was sie schneller macht als äquivalente handgeschriebene Python-Schleifen. Sie verwenden auch Lazy Evaluation (ein Element nach dem anderen erzeugen), was den Speicherverbrauch reduziert. Bei großen Datensätzen kann die Kombination aus C-Geschwindigkeit und null Zwischenlisten erhebliche Leistungsverbesserungen bringen.
Fazit
Pythons itertools-Modul ersetzt Dutzende gängiger Schleifenmuster durch einzelne Funktionsaufrufe, die schneller, lesbarer und speichereffizienter sind. Die unendlichen Iteratoren (count, cycle, repeat) handhaben Folgen ohne natürliches Ende. Die endlichen Iteratoren (chain, islice, groupby, accumulate, compress, takewhile, dropwhile) decken Filtern, Aufteilen und Aggregation ab. Die kombinatorischen Funktionen (product, permutations, combinations, combinations_with_replacement) eliminieren verschachtelte Schleifen für erschöpfende Suche.
Das Schlüsselprinzip ist Komposition. Da jede itertools-Funktion einen Iterator zurückgibt, können Sie die Ausgabe einer Funktion direkt in eine andere leiten, ohne Zwischenspeicherung. Dies ermöglicht die Verarbeitung von Datensätzen, die nicht in den Speicher passen, ein Element nach dem anderen, mit sauberem und deklarativem Code.