Historie der Frage: Das Konzept der Iterierbarkeit wurde in Python eingeführt, um die Arbeit mit Sammlungen zu vereinheitlichen: Listen, Wörterbücher, Mengen usw. Jedes Objekt, über das man mit einer for-Schleife iterieren kann, gilt als iterierbar. Dies wird durch bestimmte magische Methoden realisiert.
Problem: Python erfordert bestimmte Protokolle für die korrekte Arbeit mit Schleifen und Funktionen, die sich auf Sequenzen beziehen. Wenn der Benutzer diese Protokolle in seiner Klasse falsch implementiert, funktionieren die Standardmechanismen (for, list(), sum() usw.) nicht oder verhalten sich unerwartet.
Lösung:
Ein Objekt ist iterierbar, wenn es die Methode __iter__ implementiert. Ein Iterator ist ein Objekt, das die Methode __next__ und __iter__ hat, die self zurückgibt. In der Regel ist das von __iter__ zurückgegebene Objekt ein Iterator, aber das ist nicht zwingend erforderlich. Beispiel:
class MyRange: def __init__(self, start, end): self.start = start self.end = end def __iter__(self): self.current = self.start return self def __next__(self): if self.current < self.end: val = self.current self.current += 1 return val raise StopIteration for x in MyRange(1, 4): print(x) # 1, 2, 3
Wesentliche Merkmale:
__iter__ bestimmt.__next__ als auch __iter__ (das self zurückgibt) implementieren.__iter__ wird effektiv realisiert, wenn mehrere unabhängige Durchläufe über die Sammlung erforderlich sind.Ist die Methode next für jedes iterierbare Objekt erforderlich?
Nein. Für ein iterierbares Objekt ist nur __iter__, das einen Iterator zurückgibt, erforderlich. __next__ wird nur vom Iterator selbst implementiert. Beispielsweise hat list keine Methode __next__, ist aber iterierbar: Ihr __iter__ gibt eine Instanz des Iterators zurück.
lst = [1, 2, 3] print(hasattr(lst, '__next__')) # False
Kann ein Objekt von sich aus ein Iterator sein?
Ja, wenn es beide Methoden — sowohl __iter__ als auch __next__ — implementiert.
Kann man mehrere Iteratoren mit unabhängigem Zustand für eine Sammlung erstellen?
Ja, wenn __iter__ jedes Mal ein neues Iterator-Objekt zurückgibt.
class MyList: def __init__(self, data): self.data = data def __iter__(self): return iter(self.data)
__next__ ohne __iter__ (oder umgekehrt).Negativer Fall: Die Klasse des Iterators speichert den Zustand (z.B. den aktuellen Index) auf Klassenebene und nicht auf Instanzebene, was zu Kollisionen bei parallelen Durchläufen führt. Vorteile:
Positiver Fall:
Jeder Iterator speichert seinen Zustand in der Instanz, die in __iter__ erstellt wurde.
Vorteile: