Geschichte der Frage:
Die Funktion enumerate() erschien in Python 2.3 und ist heute der Standardweg, um gleichzeitig auf das Element und den Index des Elements beim Durchlaufen von Sammlungen zuzugreifen. Vor der Einführung von enumerate() erstellten Programmierer oft eigene Zähler oder verwendeten die Funktion range(len(sequence)), was unpraktisch und unleserlich war.
Problem:
Eine einfache for-Schleife durchläuft nur Werte. Um auf den Index zuzugreifen, wird häufig range(len(...)) verwendet, was nicht für alle iterierbaren Objekte funktioniert (zum Beispiel Generatoren, Strings und Tuples variabler Länge sowie bei Filtern). Dies führt zu Fehlern und kompliziert den Code.
Lösung:
enumerate() gibt Paare (Index, Element) zurück, was es ermöglicht, den Index des aktuellen Elements auch für nicht standardisierte Sammlungen oder gefilterte Generatoren zu erhalten. Die Funktion nimmt ein zweites optionales Argument — den Startwert des Zählers.
Beispielcode:
words = ['apple', 'banana', 'cherry'] for idx, word in enumerate(words, 1): print(f"{idx}: {word}") # Ausgabe: # 1: apple # 2: banana # 3: cherry
Wichtige Besonderheiten:
Warum verwenden Funktionen oft enumerate anstelle von range(len(seq))?
Antwort: range(len(seq)) funktioniert nur für sequenzen mit Zufriff über den Index und berücksichtigt keine Längenänderungen während der Iteration. Zudem ist es schlechter lesbar und funktioniert langsamer oder gar nicht für Generatoren. enumerate() bietet einen sicheren Zugriff auf die Index-Wert-Paare für jede iterierbare Sammlung.
Beispielcode:
# Funktioniert nicht mit einem Generator: gen = (x for x in range(5)) for i in range(len(gen)): print(i) # Fehler: Der Generator hat keine Länge
Kann man enumerate verwenden, um Elemente einer Liste während des Durchlaufens zu ändern?
Antwort: Ja, aber man muss über die Indizes iterieren, um Werte zu schreiben. Andernfalls, wenn man nur über Werte iteriert, verändert man eine Kopie des Objekts und nicht das Original.
Beispielcode:
nums = [1, 2, 3] for idx, val in enumerate(nums): nums[idx] = val * 2 # nums = [2, 4, 6]
Was gibt enumerate zurück, wenn man ihm ein Objekt übergibt, das sich während der Iteration ändert?
Antwort: Wenn die Sammlung während des Durchlaufens verändert wird (zum Beispiel Elemente gelöscht werden), kann das Verhalten unerwartet sein, da enumerate über den internen Iterator läuft, der möglicherweise durcheinandergeraten kann. Daher wird nicht empfohlen, die Sammlung während der Iteration zu ändern.
range(len(...)) für Objekte ohne Länge oder für solche, deren Länge sich ändern kann.Negativer Fall
Ein Programmer durchläuft eine Liste, indem er range(len(list)) verwendet und dabei Elemente entfernt. Das Ergebnis — die Indizes geraten durcheinander, einige Elemente werden übersprungen.
Vorteile:
Nachteile:
Positiver Fall
Verwendet enumerate(), während ein neuer Liste der benötigten Elemente erstellt wird oder ein Wert über den Index geändert wird, aber die Größe der Liste sich während der Schleife nicht ändert.
Vorteile:
Nachteile: