Iterator


aus Wikipedia, der freien Enzyklopädie
Wechseln zu: Navigation, Suche

Der Begriff Iterator stammt aus dem Bereich der Softwareentwicklung und bezeichnet einen Zeiger, mit dem die Elemente einer Menge durchlaufen werden können (z. B. eine Liste). Der Begriff leitet sich aus der mathematischen Methode der Iteration ab. Der Iterator wird insbesondere im Bereich der Datenbanken manchmal auch Cursor genannt.

Beschreibung

Ein Iterator ist ein spezieller Zeiger, der innerhalb eines Programms vom Software-Entwickler dazu verwendet werden kann, um auf Elemente einer Menge, vereinfacht eine Liste, zuzugreifen. Iteratoren arbeiten nach dem Grundprinzip "Wenn es ein weiteres Element in der Liste gibt, dann stelle es zur Verfügung."

Dies ist vereinfacht damit vergleichbar, wie man einen Text, der eine Liste von Worten ist, liest: "Wenn es ein nächstes Wort gibt, dann lies es. Wenn kein weiteres Wort mehr folgt, ist der Text beendet." In jedem als Iteration bezeichneten Zugriffs-Schritt steht somit exakt ein Wort des Textes zur Bearbeitung zur Verfügung.

Viele der in der Programmierpraxis verwendeten Iteratoren stellen über die lesende Zugriffsmöglichkeit hinaus Mechanismen zur Verfügung, die ein aktuell gelesenes Element aus der Liste entfernen oder ein neues Element in die Liste aufnehmen, sowie bei der Bearbeitung eines Textes Worte eingefügt oder gelöscht werden können.

Externe Iteratoren und das Iterator-Entwurfsmuster

Hauptartikel: Iterator (Entwurfsmuster)

Ein externer Iterator kann als eine Art Zeiger betrachtet werden, der zwei primäre Funktionen besitzt: Ein bestimmtes Element in einer Menge von Objekten referenzieren (element access genannt) sowie durch selbst-Modifizierung auf das nächste Element in der Menge zu zeigen (element traversal genannt). Abhängig von der verwendeten Programmiersprache und der Anwendung können Iteratoren zusätzliche Funktionalität sowie verschiedenes Verhalten aufweisen.

Der Hauptzweck des Iterators ist es, dem Benutzer zu erlauben, auf jedes Element in einer Menge zuzugreifen, während es ihn von der Datenstruktur der Menge isoliert. Dies befähigt die Menge, die Elemente auf jede mögliche Art und Weise zu verwalten, während sie sich dem Benutzer gegenüber so verhält, als wäre sie eine simple Sequenz oder eine Liste. Eine Iteratorklasse wird in enger Koordination mit ihrer Containerklasse, also ihrer Menge, entworfen. Üblicherweise stellt die Containerklasse die Funktionen zur Verfügung, die zur Erstellung von Iteratoren benutzt werden. Ein Zähler in einer Schleife (auch loop Counter genannt) wird manchmal auch als Schleifeniterator bezeichnet. Dabei ist zu beachten, dass ein solcher Zähler nur die element traversal Funktionalität abbildet und nicht die element access Funktionalität.

Generatoren

Eine Art, Iteratoren zu implementieren, ist es, eine spezielle Funktion zu erstellen, welche als Generator bekannt ist. Diese kann, anstatt ein Element auf einmal zurückzuliefern, mehrere Elemente in mehreren Schritten dem Benutzer zurückliefern. Die meisten Iteratoren lassen sich in natürlicher, intuitiver Art und Weise durch Generatoren abbilden. Da Generatoren ihren lokalen Status zwischen Funktionsaufrufen beibehalten, eignen sie sich hervorragend zur Implementierung von komplexen zustandsorientierten Iteratoren wie sogenannte Binärbaumtraversierer. Als Beispiel sei hier ein Generator angeführt, welcher Zahlen einer Fibonacci-Folge mit Hilfe des Pythonbefehls yield zurückliefert: <syntaxhighlight lang="python">

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b
for number in fibonacci(): # Benutze den Generator als Iterator
    print(number)

</syntaxhighlight>

Implizite Iteratoren

Mehrere Objektorientierte Sprachen wie Perl, Python, C#, Ruby sowie neuere Java-und Delphiversionen stellen eine intrinsische Art durch Elemente zu iterieren zur Verfügung, ohne dabei ein explizites Iteratorobjekt zu benutzen. Dieses kann allerdings auch vorhanden sein, ist aber nicht im Code der jeweiligen Programmiersprache verfügbar, wenn dies der Fall sein sollte.

Implizite Iteratoren manifestieren sich oft durch den foreach Befehl oder seine Äquivalente, wie unten stehendes Python Beispiel zeigt: <syntaxhighlight lang="python"> for value in iterable:

   print(value)

</syntaxhighlight>

Manchmal werden Iteratoren auch direkt vom Objekt der Datensammlung generiert, wie unten stehendes Ruby-Beispiel zeigt:

<syntaxhighlight lang="ruby"> iterable.each do |value|

 puts value

end </syntaxhighlight>

Dieser Iterationsstil wird auch internal iteration genannt, da sein Code vollständig im Kontext des zu iterierenden Objektes ausgeführt wird. Dieses kontrolliert somit sämtliche Aspekte der Iteration, der jeweilige Benutzer respektive Programmierer stellt nur die Operation für die einzelnen Iterationsschritte zur Verfügung, indem er eine anonyme Subroutine benutzt.

Sprachen, welche sogenannte Listenkomprehensionen oder ähnliche Konstrukte unterstützen, bedienen sich analog zu Python ebenfalls der impliziten Iteratoren während der Erstellung der Resultatsliste: <syntaxhighlight lang="python"> names = print(key, value)

</syntaxhighlight>

<syntaxhighlight lang=Python> for key, value in dictionary.items():

   print(key, value)

</syntaxhighlight>

Iteratoren in Python können aber auch explizit definiert und benutzt werden. Für jeden iterierbaren Sequenztypen oder jede iterierbare Klasse steht die eingebaute iter() Funktion zur Verfügung um ein Iteratorobjekt zu generieren. Mit dem Iteratorobjekt kann mit den Funktionen next(), oder __next__() zum nächsten Element navigiert werden. Ist das Ende der Menge erreicht wird ein StopIteration Fehler aufgeworfen. Das nachfolgende Beispiel zeigt eine Äquivalente Implementation von expliziten Iteratoren: <syntaxhighlight lang=Python> it = iter(sequence) while True:

   try:
       value = it.next()
   except StopIteration:
       break
   print(value)

</syntaxhighlight>

Jede benutzerdefinierte Klasse kann die Standarditeration unterstützen wenn eine _iter__() Funktion definiert wurde welche ein Iteratorobjekt generiert, der Iterator muss dann eine __next__() Funktion definieren die das nächste Element zurückgibt. Die Python-Generatoren implementieren dieses Iterationsprotokoll.

Ruby

Die Implementation der Iteratoren in Ruby unterscheidet sich von den meisten anderen Programmiersprachen: Alle Iterationen gehen dem Gedanken nach, sogenannte callback closures an Containermethoden durchzureichen. Auf diese Art und Weise implementiert Ruby nicht nur eine Basisfunktionalität an Iteratoren, sondern bildet viele Iteratorentwurfsmuster ab wie z. B. sogenanntes function mapping, Filter und sogenanntes reducing.

Ruby unterstützt des Weiteren noch eine alternative Syntax für jede Basisfunktion zur Iteration: <syntaxhighlight lang=Ruby> (0...42).each do |n|

puts n

end </syntaxhighlight> … und … <syntaxhighlight lang=Ruby> for n in 0...42

puts n

end </syntaxhighlight>

oder noch kürzer

<syntaxhighlight lang=Ruby> 42.times do |n|

puts n

end </syntaxhighlight>

Einzelnachweise

<references />

Siehe auch

Weblinks