Iteratoren und Iterablen¶
Python-Foren und Frage-und-Antwort-Websites wie Quora und Stack Overflow sind voller Fragen zu den Begriffen "Iterator" und "iterierbar". Einige möchten wissen, wie diese Begriffe definiert sind, andere suchen nach einer einfachen Möglichkeit, zu überprüfen, ob ein Objekt ein Iterator oder ein iterierbares Objekt ist. Zu diesem Zweck stellen wir eine Funktion zur Verfügung.
Wir haben gesehen, dass wir verschiedene Python-Objekte wie Listen, Tupel und Strings durchlaufen können. Zum Beispiel:
for stadt in ["Berlin", "Wien", "Zürich"]:
print(stadt)
for sprache in ("Python", "Perl", "Ruby"):
print(sprache)
for charakter in "Iteration ist einfach":
print(charakter)
Diese Form der Schleife kann als Iteration angesehen werden. Iteration ist jedoch nicht auf explizite for
-Schleifen beschränkt. Wenn Sie beispielsweise die Funktion sum()
auf einer Liste von ganzzahligen Werten aufrufen, wird ebenfalls eine Iteration durchgeführt.
Was ist der Unterschied zwischen einem iterierbaren Objekt (Iterable) und einem Iterator?¶
Iterables und Iteratoren haben Ähnlichkeiten: Über beide können Sie mit einer for
-Schleife iterieren. Jeder Iterator ist ein Iterable, aber nicht jedes Iterable ist ein Iterator. Ein Beispiel: Eine Liste ist ein Iterable, aber keine Liste ist von sich aus ein Iterator. Ein Iterator kann jedoch mit der Funktion iter()
aus einem Iterable erzeugt werden. Damit dies möglich ist, muss die Klasse des Objekts entweder die Methode __iter__
implementieren, die einen Iterator zurückgibt, oder eine Methode __getitem__
, die den sequentiellen Zugriff über Indizes (beginnend bei 0) ermöglicht.
Ein Iterator hingegen ist ein Objekt, das über die Methode __next__
verfügt. Diese Methode wird aufgerufen, wenn Sie die Funktion next()
verwenden.
Was passiert hinter den Kulissen, wenn eine for-Schleife ausgeführt wird?¶
Die for
-Schleife ruft zu Beginn iter()
für das Objekt auf, über das sie iterieren soll. Dieses Objekt muss ein sogenanntes Containerobjekt (ein Iterable) sein. Wenn der Aufruf von iter()
erfolgreich ist, wird ein Iterator-Objekt zurückgegeben, das die Methode __next__
implementiert. Diese Methode greift nacheinander auf die Elemente des Objekts zu. Wenn keine weiteren Elemente mehr vorhanden sind, löst die Methode __next__
eine StopIteration
-Ausnahme aus, die das Ende der Iteration signalisiert. Sobald die for
-Schleife die StopIteration
-Ausnahme abfängt, wird sie beendet.
Sie können die Methode __next__
auch explizit durch die eingebaute Funktion next()
aufrufen. So funktioniert es:
städte = ["Berlin", "Wien", "Zürich"]
iterator_obj = iter(städte)
print(iterator_obj)
print(next(iterator_obj))
print(next(iterator_obj))
print(next(iterator_obj))
# StopIteration wird ausgelöst, wenn keine
# weiteren Elemente vorhanden sind
Wenn wir noch einmal next(iterator_obj)
aufrufen würden, würde eine StopIteration
-Ausnahme ausgelöst.
Die folgende Funktion is_iterable
gibt True
zurück, wenn das Objekt obj
iterierbar ist, andernfalls False
:
def is_iterable(obj):
try:
iter(obj)
return True
except TypeError:
return False
for element in [34, [4, 5], (4, 5), {"a":4}, "dfsdf", 4.5]:
print(element, "iterable: ", is_iterable(element))
Wir haben beschrieben, wie ein Iterator funktioniert. Wenn Sie Ihrer Klasse also ein Iteratorverhalten hinzufügen möchten, müssen Sie Ihrer Klasse die Methoden __iter__
und __next__
hinzufügen.
- Die Methode
__iter__
gibt ein Iteratorobjekt zurück. - Wenn die Klasse eine
__next__
-Methode enthält, reicht es aus, dass die__iter__
-Methodeself
zurückgibt, d. h. einen Verweis auf sich selbst.
Hier ist ein Beispiel für eine benutzerdefinierte Klasse, die Iteratorverhalten implementiert:
class Reverse:
"""
Erstellt Iteratoren zum Rückwärtslaufen einer Sequenz.
"""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
lst = [34, 978, 42]
lst_rückwärts = Reverse(lst)
for el in lst_rückwärts:
print(el)