Python Iterators
Table of Contents
Iteratoren sind Objekte, über die iteriert werden kann. In diesem Tutorial lernen Sie, wie Iteratoren funktionieren und wie Sie mit den Methoden __iter__ und __next__ einen eigenen Iterator bauen können.
Iterators in Python
Iterators sind überall in Python. Sie sind elegant implementiert in for
loops, comprehensions, generators etc. sind aber in Sichtweite verborgen.
Iterator in Python ist einfach ein Objekt, über das iteriert werden kann. Ein Objekt, das Daten zurückgibt, ein Element nach dem anderen.
Technisch gesehen ist ein Python iterator object muss zwei spezielle Methoden implementieren, __iter__()
und __next__()
, zusammenfassend genannt iterator protocol.
Ein Objekt wird als iterabel bezeichnet, wenn wir von ihm einen Iterator erhalten können. Die meisten eingebauten Container in Python wie: list, tuple, string etc. sind iterable.
Die iter()
Funktion (die ihrerseits die Funktion __iter__()
Methode) gibt einen Iterator von ihnen zurück.
Iterating Through an Iterator
Wir verwenden die next()
Funktion, um manuell durch alle Elemente eines Iterators zu iterieren. Wenn das Ende erreicht ist und keine Daten mehr zurückgegeben werden können, wird die Funktion StopIteration
Ausnahme. Es folgt ein Beispiel.
# define a list my_list = [4, 7, 0, 3] # get an iterator using iter() my_iter = iter(my_list) # iterate through it using next() # Output: 4 print(next(my_iter)) # Output: 7 print(next(my_iter)) # next(obj) is same as obj.__next__() # Output: 0 print(my_iter.__next__()) # Output: 3 print(my_iter.__next__()) # This will raise error, no items left next(my_iter)
Output
4 7 0 3 Traceback (most recent call last): File "<string>", line 24, in <module> next(my_iter) StopIteration
Eine elegantere Art der automatischen Iteration ist die Verwendung der for loop. Mit dieser können wir über jedes Objekt iterieren, das einen Iterator zurückgeben kann, z. B. Liste, String, Datei usw.
>>> for element in my_list: ... print(element) ... 4 7 0 3
Working of for loop for Iterators
Wie wir im obigen Beispiel sehen, ist die for
loop in der Lage war, automatisch durch die Liste zu iterieren.
In der Tat ist diefor
Schleife kann über jede beliebige Iterable iterieren. Schauen wir uns nun genauer an, wie die for
Schleife ist tatsächlich in Python implementiert.
for element in iterable: # etwas mit Element machen
Ist tatsächlich implementiert als.
# ein Iterator-Objekt aus dieser Iterable erzeugen iter_obj = iter(iterable) # infinite loop while True: try: # das nächste Element holen element = next(iter_obj) # etwas mit Element machen except StopIteration: # wenn StopIteration ausgelöst wird, Abbruch der Schleife break
So wird intern die for
Schleife erzeugt ein Iterator-Objekt, iter_obj
durch den Aufruf iter()
auf die Iterable..
Ironischerweise ist diese for
loop ist eigentlich eine unendliche while loop.
Innerhalb der Schleife ruft es next()
um das nächste Element zu erhalten und führt den Körper der for
loop mit diesem Wert. Nachdem alle Elemente erschöpft sind, StopIteration
ausgelöst, die intern abgefangen wird und die Schleife beendet. Beachten Sie, dass jede andere Art von Ausnahme durchgelassen wird.
Building Custom Iterators
Einen Iterator von Grund auf zu bauen ist in Python einfach. Wir müssen nur die __iter__()
und der __next__()
methods.
Die __iter__()
Methode gibt das Iterator-Objekt selbst zurück. Falls erforderlich, kann eine Initialisierung durchgeführt werden.
Die __next__()
Methode muss das nächste Element in der Sequenz zurückgeben. Bei Erreichen des Endes und bei nachfolgenden Aufrufen muss sie StopIteration
.
Hier zeigen wir ein Beispiel, das uns in jeder Iteration die nächste Potenz von 2 liefert. Der Potenzexponent beginnt bei Null und reicht bis zu einer benutzerdefinierten Zahl.
Wenn Sie noch keine Ahnung von objektorientierter Programmierung haben, besuchen Sie Python Object-Oriented Programming.
class PowTwo: """Klasse zum Implementieren eines Iterators von Zweierpotenzen""" def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # ein Objekt erstellen numbers = PowTwo(3) # eine Iterable aus dem Objekt erzeugen i = iter(numbers) # Mit next zum nächsten Iterator Element gelangen print(next(i)) print(next(i)) print(next(i)) print(next(i)) print(next(i))
Output
1 2 4 8 Traceback (most recent call last): File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module> print(next(i)) File "<string>", line 18, in __next__ raise StopIteration StopIteration
Wir können auch eine for
loop um über unsere Iterator klasse zu iterieren.
>>> for i in PowTwo(5): ... print(i) ... 1 2 4 8 16 32
Python Infinite Iterators
Es ist nicht notwendig, dass das Element in einem Iterator-Objekt erschöpft sein muss. Es kann unendliche Iteratoren geben (die nie enden). Beim Umgang mit solchen Iteratoren müssen wir vorsichtig sein.
Hier ist ein einfaches Beispiel, um unendliche Iteratoren zu demonstrieren.
Die built-in Funktion iter()
kann mit zwei Argumenten aufgerufen werden, wobei das erste Argument ein aufrufbares Objekt (Funktion) sein muss und das zweite der Sentinel ist. Der Iterator ruft diese Funktion auf, bis der zurückgegebene Wert gleich dem Sentinel ist.
>>> int() 0 >>> inf = iter(int,1) >>> next(inf) 0 >>> next(inf) 0
Wir können sehen, dass die int()
Funktion gibt immer 0 zurück. Daher wird sie als iter(int,1)
wird einen Iterator zurückgeben, der int()
bis der zurückgegebene Wert gleich 1 ist. Dies geschieht nie und wir erhalten einen unendlichen Iterator.
Wir können auch unsere eigenen unendlichen Iteratoren bauen. Der folgende Iterator wird theoretisch alle ungeraden Zahlen zurückgeben.
class InfIter: """Infinite Iterator, um alle ungeraden Zahlen zurückzugeben""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num
Ein Beispiellauf würde folgendermaßen aussehen.
>>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7
Und so weiter…
Achten Sie darauf, dass Sie eine Abbruchbedingung einfügen, wenn Sie über diese Arten von unendlichen Iteratoren iterieren.
Der Vorteil der Verwendung von Iteratoren ist, dass sie Ressourcen sparen. Wie oben gezeigt, könnten wir alle ungeraden Zahlen erhalten, ohne das gesamte Zahlensystem im Speicher zu speichern. Wir können (theoretisch) unendlich viele Elemente in einem endlichen Speicher haben.
Es gibt einen einfacheren Weg, Iteratoren in Python zu erstellen. Um mehr zu erfahren, besuchen Sie: Python-Generatoren (link) mit yield.