Iterable in Python
Nach dem Start einer Python -Implementation gibt es nur wenige Iteratoren.
Trotzdem sind Iteratoren nützlich und spielen eine wichtige Rolle.
Der übliche Weg zu Beschaffung eines Iterators besteht darin, ein anderes Objekt zu nutzen, das einen Iterator liefern kann.
Solche Iteratorlieferanten werden Iterable genannt. – „Iterable“ kann auch als Adjektiv verwendet werden: Ein Iterables ist ein iterables Objekt.
Wird die Funktion »iter« mit einem Iterablen als Argument aufgerufen, so ergibt sich ein Iterator, von dem dann mit »next« weitere Objekte erhalten werden können.
Um Objekte von einem Iterablen zu erhalten, wird einem ›iter‹ verwendet und danach wiederholt ›next‹.
- Abbildung (mit den englischen Wörtern “iterable ” und “iterator ”)
iter next
iterable --------------------> iterator --------------------> Objekt
Wie bei einem Iterator stellen wir uns auch bei einem Iterablen vor, daß es die Objekte „enthält“, die durch wiederholte Aufrufe von »next« auf seinem Iterator erhalten werden können. (Diese Objekte müssen aber nicht wirklich alle in dem Iterablen gespeichert sein, es kann auch sein, daß sie erst bei Bedarf erzeugt werden.)
Wenn wir sagen, daß ein Iterables Objekte liefere, so meinen wir damit, daß ein vom Iterablen erzeugter Iterator jene Objekte liefert.
Iterable Zeichenfolgen
str-Zeichenfolgen sind iterabel.
»iter( "ab" )« ist ein Iterator, der jeweils ein Zeichen von »ab« liefert. – Der erste Aufruf von »next« auf diesem Iterator ergibt also das erste Zeichen der str-Zeichenfolge.
Mit „ein Aufruf einer Funktion auf einem Objekt“ ist im voranstehendem Satz der Aufruf der Funktion mit diesem Objekt als Argumentwert gemeint.
- Konsolenprotokoll
next( "ab" )
TypeError: 'str' object is not an iterator
- Konsolenprotokoll
next( iter( "ab" ))
'a'
- Konsolenprotokoll
iterable = "ab"
iterator = iter( iterable )
object = next( iterator )
print( object )
'a'
object = next( iterator )
print( object )
'b'
object = next( iterator )
StopIteration
iterator = iter( iterable )
object = next( iterator )
print( object )
'a'
object = next( iterator )
print( object )
'b'
object = next( iterator )
StopIteration
Mit ›next‹ wird ein weiteres Objekt beantragt, aber der Antrag kann mit ›StopIteration‹ abgelehnt werden.
- Abbildung
iter next
"ab" --------------------> Iterator -------.------------> "a"
|
'------------> "b"
|
StopIterationiter next
"ab" --------------------> Iterator -------.------------> "a"
|
'------------> "b"
|
StopIteration
Im Gegensatz zu Iteratoren erlauben Iterable also mehrfaches Durchlaufen, indem mit ›iter‹ ein neuer Iterator angefordert wird.
Eine leere str-Zeichenfolge hat allerdings kein erstes Zeichen.
- Konsolenprotokoll
next( iter( "" ))
StopIteration
Wir sagen kurz: „Das Iterable ›"ab"‹ liefert die beiden Objekte ›"a"‹ und ›"b"‹.“, obwohl wir eigentlich sagen müßten „Der vom Iterable ›"ab"‹ gelieferte Iterator liefert uns die beiden Objekte ›"a"‹ und ›"b"‹.“
»next« als Wirkwertfunktion
Die Wertfunktion »next« bewirkt auch eine Änderung. Das Argumentobjekt wird auf die nächste Position weitergestellt, also verändert.
Unten ist der Wert aller Vorkommen von »_« das gleiche Objekt, nämlich das Ergebnis des Aufrufs »iter( "ab" )«. Die Werte der Aufrufe »next( _ )« sind jedoch jeweils unterschiedlich, da der Zustand des Objekts »_« jedesmal ein anderer ist, weil er vom vorigen Aufruf »next( _ )« verändert wurde.
- Konsolenprotokoll
iter( "ab" )
<str_iterator object …>
print( next( _ ))
'a'
print( next( _ ))
'b'
print( next( _ ))
StopIteration
print( next( _ ))
StopIteration
Iterable Listen
Listen sind ebenfalls iterabel.
Eine Liste ergibt sich beispielsweise beim Aufruf von »dir«.
- Konsolenprotokoll
dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
next( dir() )
TypeError: 'list' object is not an iterator
next( iter( dir() ))
'__annotations__'
- Konsolenprotokoll
iter( dir() )
<list_iterator object …>
print( next( _ ))
__annotations__
print( next( _ ))
__builtins__
print( next( _ ))
__doc__
print( next( _ ))
__loader__
print( next( _ ))
__name__
print( next( _ ))
__package__
print( next( _ ))
__spec__
print( next( _ ))
StopIteration
print( next( _ ))
StopIteration
Iterable Tupel
Auch Tupel sind iterabel.
Iterable Iteratoren
Alle Iteratoren sind „pro forma“ auch Iterable, insofern ›iter‹ mit ihnen aufgerufen werden kann, doch liefern sie dann nur wieder sich selbst als Iterator.
- Konsolenprotokoll
from multiprocessing.pool import job_counter
next( job_counter )
0
next( job_counter )
1
next( job_counter )
2
x = iter( job_counter )
x is job_counter
True
next( x )
3
next( job_counter )
4
next( x )
5
next( job_counter )
6
Iterable erkennen
Um zu erkennen, ob etwas iterabel ist, kann in der Dokumentation nachgelesen werden.
Es ist auch möglich, versuchsweise ›iter‹ damit aufzurufen. Es ist dann iterabel, wenn sich keine Fehlermeldung, sondern ein Objekt ergibt. Jedoch könnte solch ein Aufruf auch unerwünschte Folgen haben, so daß es etwas riskant ist, es einfach auszuprobieren.
- Konsole
iter( 2 )
TypeError: 'int' object is not iterable
iter( 'ab' )
<str_iterator object at 0x000000000248EDD0>
›enumerate‹
›enumerate‹ ergibt für ein Iterables einen Iterator, der jeweils Paare liefert, die vor dem Objekt noch eine laufende Nummer enthalten. So lassen sich Objekte numerieren.
- Konsolenprotokoll
e = enumerate( "elf" )
next( e )
(0, 'e')
next( e )
(1, 'l')
next( e )
(2, 'f')
next( e )
StopIteration
next( e )
StopIteration
Warum Iterable, reichen nicht Iteratoren?
Ein Iterator kann nur einmal durchlaufen werden und ist danach meist für immer erschöpft.
- Konsolenprotokoll
e = enumerate( "elf" )
next( e )
(0, 'e')
next( e )
(1, 'l')
next( e )
(2, 'f')
next( e )
StopIteration
next( e )
StopIteration
Von einem Iterablen kann mit »iter« immer wieder ein neuer Iterator für dasselbe Objekt abgeholt werden. Solche ein neuer Iterator beginnt jeweils immer wieder am Anfang. So ist es auf eine einheitliche Weise möglich, ein Objekt mehrfach zu durchlaufen.
(Im obigen Beispiel könnte zwar erneut »enumerate« aufgerufen werden, aber dies ist nicht auf andere Iteratoren übertragbar. Bei Iterablen kann stehts für alle Iterablen in einheitlicher Weise »iter« verwendet werden, um einen neuen Interator zu erhalten.)
- Konsolenprotokoll
iter( "ab" )
<str_iterator object …>
print( next( _ ))
'a'
print( next( _ ))
'b'
iter( "ab" )
<str_iterator object …>
print( next( _ ))
'a'
print( next( _ ))
'b'
Die natürlichen Zahlen als Iterables
Da es unendlich viele natürliche Zahlen gibt, können sie nicht alle im Computer abgespeichert werden. Es ist jedoch möglich, ein Iterables zu erzeugen, daß alle natürlichen Zahlen liefert, da sie dazu nicht alle gleichzeitig abgespeichert werden müssen.
Das Iterable »count()« liefert alle natürlichen Zahlen (beginnend mit Null).
- Konsolenprotokoll (mit den englischen Wörtern “iterable ” und “iterator ”)
from itertools import count
iterable = count()
iterator = iter( count() )
print( next( iterator ))
0
print( next( iterator ))
1
print( next( iterator ))
2
Iterable manifestieren
Iterable können Iteratoren liefern und so als Quellen für Objekte dienen. Es könnte aber sein, daß diese Objekte erst beim Aufruf von ›next‹ erzeugt werden.
Im Gegensatz dazu sind die in einem Tupel enthaltenen Objekte alle schon im Speicher vorhanden.
Daher könnte es sein, daß ein Iterables, daß Milliarden von Objekten liefert, nur wenig Speicherplatz benötigt. Ein Tupel mit Milliarden von Objekten würde aber relativ viel Speicherplatz kosten.
Wenn ›tuple‹ mit einem Iterablen als Argument aufgerufen wird, so wird ein Tupel im Speicher erzeugt, daß alle vom Iterablen gelieferten Objekte enthält. Dazu wird aus dem Iterablen zunächst mit ›iter‹ ein Iterator erzeugt, und von dem werden dann alle Objekte abgerufen bis ›StopIteration‹ erscheint und im Tupel gespeichert.
- Konsolenprotokoll
iterable = "ab"
tuple( iterable )
('a', 'b')
Wir sagen dazu auch, daß das Iterable als Tupel manifestiert wurde – das heißt, daß das Tupel nun alle Werte des Iterablen so enthält, daß diese jeweils im Tupel abgespeichert wurden.
⚠ Warnung Ein Versuch, »tuple( count() )« auszuwerten, könnte Computer vorübergehend (bis zu einem Neustart) unbrauchbar machen und dadurch zu Datenverlust führen. Daher sollte dies vermieden werden!
Bei der Auswertung von »tuple( count() )« könnte versucht werden, alle Zahlen von ›count()‹ abzurufen und abzuspeichern, dadurch könnte so viel Speicher belegt werden, daß der Computer keinen Speicherplatz für wichtige Systemoperationen mehr hat.
Jeder Iterator ist iterabel
Zumindest formal ist jeder Iterator auch iterabel, doch ergibt der Aufruf von »iter« auf einem Iterator wieder den Iterator selber, ohne daß er auf diese Weise zurückgesetzt wird. Trotzdem ist dies hilfreich, weil auf diese Weise jeder Iterator dort eingesetzt werden kann, wo ein Iterables erwartet wird.
- Konsolenprotokoll
i = iter( "ab" )
tuple( i )
('a', 'b')
- Zitat *
- “Iterator objects also need to implement this method; they are required to return themselves.”
- The Python Language Reference, Release 3.9.0a3, 3.3.7 Emulating container types
Motivation
Oft findet man in der Python -Dokumentation die Aussage, daß bestimmte Objekte iterabel sein sollen.
In dem folgenden Zitat wird beispielweise gesagt, daß das Argument von ›all‹ iterabel sein muß.
- Zitat
- “all(iterable)
- Return True if all elements of the iterable are true (or if the iterable is empty).”
- The Python Library Reference, Release 3.9.0a3
Anwendungsgebiete von Iterablen
- Ein iterables Objekt erlaubt es, nach der Erschöpfung eines Iterators, erneut einen Iterator zu beantragen.
- Oft liefern alle Iteratoren eines Iterablen hintereinander dieselbe Abfolge von Werte, so daß dann eine Abfolge von Werten mehrfach durchlaufen werden kann, indem mehrere Iteratoren beantragt werden. (In diesem Fall kann beim ersten Durchlauf beispielsweise die Anzahl der Werte ermittelt werden.)
- Ansonsten gelten für Iterable dieselben Anwendungsgebiete wie für Iteratoren, da Iterable ja nur dazu da sind, Iteratoren zu erhalten.
Übersicht Iterable und Funktoren
- Iteratoren
from multiprocessing.pool import job_counter
job_counterfrom sys import stdin
stdin- Ergebnisse von »enumerate«
- Ergebnisse von »iter«
- Iterable
from itertools import count
count()- alle Iteratoren (formal)
- str-Objekte
- list-Objekte
- tuple-Objekte
- Funktoren, die Iteratoren akzeptieren
next
iter
- Funktoren, die Iterable akzeptieren
iter
Übungsfragen
? Übungsfrage 0
Welche Ausgabe ergibt die folgende Anweisungsfolge?
- Anweisungen (mit den englischen Wörtern “iterable ” und “iterator ”)
iterable = 'abc'
iterator = iter( iterable )
print( next( iterator )+ next( iterator ))
? Übungsfrage 1
Welche Ausgabe ergibt die folgende Anweisungsfolge?
- Anweisungen
G = 'def'
Q = iter( G )
R = iter( G )
print( next( Q )+ next( R ))
? Übungsfrage 2 ⃗
Welche Ausgabe ergibt die folgende Anweisungsfolge?
- Anweisungen (mit den englischen Wörtern “iterable ” und “iterator ”)
Text = ''
iterable = 'abc'
iterator = iter( iterable )
Text = next( iterator )+ Text
Text = next( iterator )+ Text
Text = next( iterator )+ Textprint( Text )
? Übungsfrage 3 ⃗
Welche Ausgabe ergibt die folgende Anweisungsfolge?
- Anweisungen (mit den englischen Wörtern “iterable ” und “iterator ”)
Text = ''
iterable = 'abc'
iterator = iter( iterable )
Text = next( iterator )+ Text
Text = next( iterator )+ Textiterator = iter( iterable )
Text = next( iterator )+ Text
Text = next( iterator )+ Textprint( Text )
? Übungsfrage ⃗
Können Sie den Wert der Auswertung von »next( iter( next( iter( dir() ))))« vorhersagen?
- Konsolenprotokoll
dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
next( iter( next( iter( dir() ))))
- ?
„Iterables“
Iterables
woertliche Bedeutung: Ein Objekt, (ueber) das iteriert werden kann
Wortklasse: Nomen
Artikel: das
Flexionsklasse: AdjektivischStarke Flexion (ohne Artikel)
Singular Plural
Neutrum Neutrum
Artikel Nomen Artikel NomenNominativ - Iterables - Iterable
Akkusativ - Iterables - Iterable
Dativ - Iterablem - Iterablen
Genitiv - Iterablen - IterablerSchwache Flexion (mit bestimmtem Artikel)
Singular Plural
Neutrum Neutrum
Artikel Nomen Artikel NomenNominativ das Iterable die Iterablen
Akkusativ das Iterable die Iterablen
Dativ dem Iterablen den Iterablen
Genitiv des Iterablen der IterablenGemischte Flexion (mit ein, kein, Possessivpronomen u.a.)
Singular Plural
Neutrum Neutrum
Artikel Nomen Artikel NomenNominativ ein Iterables keine Iterablen
Akkusativ ein Iterables keine Iterablen
Dativ einem Iterablen keinen Iterablen
Genitiv eines Iterablen keiner Iterablen