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.