(c) 2023 Technische Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever - Impressum
Die meisten Containerobjekte können mit einer for-Schleife angeprochen werden:
for element in [1, 2, 3]:
print(element)
for element in (1, 2, 3):
print(element)
for key in {'one':1, 'two':2}:
print(key)
for char in "123":
print(char)
for line in open("myfile.txt"):
print(line, end='')
1 2 3 1 2 3 one two 1 2 3 Dies ist ein Testfile mit Text in mehreren Zeilen
Diese Art von Zugriff auf Containerobjekte ist klar, prägnant und bequem und beruht auf der Verwendung von Iteratoren. Die Verwendung von Iteratoren durchdringt und vereinheitlicht Python und ist eine wichtige Grundlage für das Schreiben von funktionalen Programmen.
Ein Iterator ist ein Objekt, das einen Datenstrom darstellt; Dieses Objekt gibt die Daten jeweils als ein Element nach dem anderen zurück.
Hinter den Kulissen ruft die for-Schleife die Builtin-Funktion iter() auf das entsprechende Containerobjekt auf. Diese Funktion gibt ein Iteratorobjekt zurück, in dem die Methode __next__() definiert sein muss und die jeweils ein Element nach dem anderen aus dem Container zurückliefert. Die Methode __next__() darf auch keine Argumente annehmen. Wenn es keine Elemente mehr gibt, wirft __next__() eine StopIteration-Ausnahme, welche die for-Schleife beendet. Die Methode __next__() kann mit Builtin-Funktion next() aufgerufen werden; Das folgende Beispiel zeigt, wie alles funktioniert:
s = 'abc'
it = iter(s)
it
<str_iterator at 0x7fccc35b1ac8>
next(it)
'a'
next(it)
'b'
next(it)
'c'
next(it)
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-8-2cdb14c0d4d6> in <module>() ----> 1 next(it) StopIteration:
Hier ein weiteres Beispiel, diesmal mit einer Liste anstelle einer Zeichenkette:
L = [1,2,3]
it = iter(L)
it
<list_iterator at 0x7fcce43acbe0>
it.__next__() # identisch mit next(it)
1
next(it)
2
next(it)
3
next(it)
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-13-2cdb14c0d4d6> in <module>() ----> 1 next(it) StopIteration:
Allgemein gesprochen, nimmt die Builtin-Funktion iter() ein beliebiges Objekt und versucht, einen Iterator zurückzugeben. Der Iterator gibt dann über die Methode __next__() den Inhalt bzw. die Elemente des Objekts Schritt für Schritt zurück. Wenn das entsprechende Objekt keine Iteration unterstützt, wird ein TypeError geworfen. Mehrere der in Python integrierten Datentypen unterstützen die Iteration, die häufigsten sind Listen und Dictionaries. Ein Objekt heißt iterabel, wenn es einen Iterator dafür gibt.
Nachdem nun die Algorithmik hinter dem Iterator-Protokoll bekannt ist, ist es einfach, das Iterator-Verhalten in eine Klasse einzubinden. Es muss eine __iter__()-Methode definiert werden, die ein Objekt mit einer __next__()-Methode zurückgibt. Wenn in der Klasse die Methode __next__() definiert ist, dann kann die Methode __iter__() einfach self zurückgeben:
class Reverse:
"""Iterator um eine Sequenz rückwärts zu durchlaufen"""
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]
rev = Reverse('spam')
iter(rev)
<__main__.Reverse at 0x7fccc356eba8>
for char in rev:
print(char)
m a p s
%%Mooc MoocStringAssessment
Python erwartet iterable Objekte in verschiedenen Kontexten, die wichtigste ist die - wie oben bereits angesprochen und eingeführt - for-Schleife. In der Anweisung for X in Y muss Y ein Iterator oder ein Objekt sein, für das die Builtin-Funktion iter() einen Iterator erzeugen kann. Die folgenden beiden Aussagen sind gleichwertig:
for i in iter(obj):
print(i)
for i in obj:
print(i)
Die Elemente von Iteratoren sind per se nur über die __next__()-Methode aufrufbar. Sie können jedoch als Listen oder Tupel mithilfe der list() oder tuple() Konstruktorfunktionen materialisiert werden:
L = [1,2,3]
iterator = iter(L)
iterator
<list_iterator at 0x7fccc3574080>
tuple(iterator)
(1, 2, 3)
Das Entpacken von Sequenzen (sequence unpacking) unterstützt ebenfalls Iteratoren: Wenn bekannt ist, dass ein Iterator N Elemente zurückgibt, können dieser in ein N-Tupel ausgepackt werden:
L = [1,2,3]
iterator = iter(L)
a,b,c = iterator
a,b,c
(1, 2, 3)
Builtin-Funktionen wie max() und min() können ein einziges Iterator-Argument aufnehmen und das größte oder kleinste Element zurückgeben. Die Operatoren in und not in unterstützen ebenfalls Iteratoren: X in iterator ist wahr, wenn X in dem vom Iterator zurückgegebenen Datenstrom gefunden wird.
Iteratoren müssen nicht endlich sein; Es kann vollkommen vernünftig sein, einen Iterator zu schreiben, der einen unendlichen Datenstrom erzeugt. Allerdings kann bei einem unendlichen Iterator offensichtlich ein Problem auftauchen: max() oder min() wird niemals zurückkehren und wenn das Element X nicht im Datenstrom enthalten ist, kehren auch die Operatoren in und not in entsprechend nicht zurück.
Zu beachten ist, dass man in einem Iterator nur vorwärts gehen kann. Es gibt keine Möglichkeit, das vorherige Element zu erhalten, den Iterator zurückzusetzen oder eine Kopie davon zu machen. Iterator-Objekte können optional diese zusätzlichen Fähigkeiten bereitstellen, aber das Iterator-Protokoll schreibt nur die Methode __next__() zwingend vor. Funktionen können daher alle Ausgaben des Iterators aufbrauchen, und wenn etwas anderes mit dem gleichen Stream gemacht werden muss, muss ein neuer Iterator erstellt werden.
Wir haben schon gesehen, wie Listen und Tupel Iteratoren unterstützen. In der Tat wird jeder Sequenz-Typ in Python, wie z.B. Zeichenketten (Strings), automatisch die Erstellung eines Iterators unterstützen.
Das Aufrufen von iter() auf ein Dictionary gibt einen Iterator zurück, der über die Schlüsselwörter des Wörterbuchs läuft:
m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
for key in m:
print(key, m[key])
Jan 1 Feb 2 Mar 3 Apr 4 May 5 Jun 6 Jul 7 Aug 8 Sep 9 Oct 10 Nov 11 Dec 12
Zu Beachten ist, dass die Reihenfolge im Wesentlichen zufällig ist, weil sie auf der Reihenfolge des Hash-Algorithmus für die Objekte im Dictionary basiert.
Das Anwenden von iter() auf ein Dictionary läuft immer über die Schlüsselwörter, aber Dictionaries haben Methoden, die andere Iteratoren zurückgeben. Wenn über Werte oder Schlüssel/Wert-Paare iteriert werden soll, dann können die Methoden values() oder items() explizit aufgerufen werden, um einen entsprechenden Iterator zu erhalten.
Der dict()-Konstruktor kann einen Iterator akzeptieren, der einen endlichen Datenstrom von (key,value)-Tupeln zurückgibt:
L = [('Italy', 'Rome'), ('France', 'Paris'), ('US', 'Washington DC')]
dict(iter(L))
{'France': 'Paris', 'Italy': 'Rome', 'US': 'Washington DC'}
Files also support iteration by calling the readline() method until there are no more lines in the file. This means you can read each line of a file like this:
Dateien unterstützen ebenfalls die Iteration, indem die readline()-Methode aufrufen, bis keine weiteren Zeilen mehr in der Datei vorhanden sind. Dies bedeutet, dass eine Datei wie folgt gelesen werden kann:
for line in file:
# hier kann irgendetwas mit der Zeile gemacht werden
...
Sets können ihren Inhalt von einem Iterator bekommen und man kann über die Elemente des Sets iterieren:
S = {2, 3, 5, 7, 11, 13}
for i in S:
print(i)
2 3 5 7 11 13
%%Mooc MoocMultipleChoiceAssessment
Es sind die folgenden Objekte gegeben:
%%Mooc Video
%%Mooc WebReference
https://docs.python.org/3/tutorial/classes.html#iterators
Hinweis: Kurze Einführung in Iteratoren
%%Mooc WebReference
https://docs.python.org/3/howto/functional.html#iterators
Hinweis: Iteratoren als Grundlage funktionaler Programmierung