ProgrammierungBackend-Entwickler

Was ist ein iterierbares Objekt in Python und wie implementiert man richtig ein benutzerdefiniertes iterierbares Objekt?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

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:

  • Iterierbarkeit wird durch das Vorhandensein der Methode __iter__ bestimmt.
  • Ein Iterator muss sowohl __next__ als auch __iter__ (das self zurückgibt) implementieren.
  • Die Rückgabe eines neuen Objekts in __iter__ wird effektiv realisiert, wenn mehrere unabhängige Durchläufe über die Sammlung erforderlich sind.

Fangfragen.

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)

Typische Fehler und Antipatterns

  • Implementierung nur von __next__ ohne __iter__ (oder umgekehrt).
  • Speicherung des Zustands auf Klassenebene anstelle von Instanzebene, was zu Fehlern bei wiederholten Durchläufen führt.

Beispiel aus dem Leben

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:

  • Weniger Speicher (nur ein Index). Nachteile:
  • Fehler bei gleichzeitiger Iteration durch zwei Schleifen.

Positiver Fall: Jeder Iterator speichert seinen Zustand in der Instanz, die in __iter__ erstellt wurde. Vorteile:

  • Korrekte Funktion mehrerer Iteratoren. Nachteile:
  • Unbedeutend höherer Speicherverbrauch.