Unterscheidung: Generator, Iterator, iter(), next(), __iter__(), __next__()

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
GabrielleChanel
User
Beiträge: 42
Registriert: Dienstag 13. April 2021, 11:54

Donnerstag 17. Juni 2021, 19:11

Hallo, ich habe etwas ein Durcheinander mit Generator, Iterator, iter(), next(), __iter__() und __next__(). Kann mir jemand bitte Klarheit verschaffen?
Am besten wäre ein Beispiel um diese zwei Fragen zu veranschaulichen, danke :)

1. Was unterscheidet diese beiden voneinander?
<list_iterator object at 0x000001C73...>
<generator object ClassName.__iter__ at 0x000001C73...>

2. iter() und next() können mit ihrer Spezialmethode __iter__() und __next__() "überschrieben" werden. Was ich noch nicht verstehe ist wann muss ich nur __iter__() implementieren und wann muss ich auch noch ein __next__() implementieren?
"Those who can imagine anything, can create the impossible." Alan Turing
Benutzeravatar
__blackjack__
User
Beiträge: 9085
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 17. Juni 2021, 19:44

@GabrielleChanel: Ad 1. Ein Iterator hat eine `__iter__()`-Methode die einfach nur `self` zurück gibt, und eine `__next__()`-Methode die entweder das nächste Objekt liefert oder `StopIteration` auslöst wenn es kein nächstes Objekt gibt.

Bei einem Generator kommen die Methoden `close()`, `send()`, und `throw()` zu dem was ein Iterator hat noch dazu. Das sollte aber auch irgendwo dokumentiert sein.

Ad 2. Das kommt darauf an. Bei einem Iterator musst Du beides implementieren, so wie in Ad 1 beschrieben. Wenn ein Objekt iterierbar sein soll, dann nur `__iter__()` und das muss einen Iterator liefern. Das kann auch ein Generator sein, denn das ist ja auch ein Iterator. `__next__()` braucht man eher sehr selten, weil es in der Regel einfacher ist entweder eine Generatorfunktion zu schreiben, oder sich was iterierbares aus anderen Werkzeugen (`itertools`, `map()`, `filter()`, `more_itertools`, Generatorausdruck, …) zu basteln statt eine komplette Klasse nur für einen Iterator zu schreiben.
“When we write programs that "learn", it turns out that we do and they don't.” — Alan J. Perlis
GabrielleChanel
User
Beiträge: 42
Registriert: Dienstag 13. April 2021, 11:54

Freitag 18. Juni 2021, 09:54

@__blackjack__ vielen Dank für deine Erläuterungen. Es wird mir nun langsam klarer. Noch eine Frage bezüglich __next__() Methode. Bei dieser Methode geht es darum zu vergleichen, ob noch ein Element übrig ist, wieso verwendet man aber kein len()? Oder sogar ein (len())-1, wenn man kein StopIteration Error will? Ich weiss nicht wie es dann implementiert werden soll, deswegen habe ich hier einen etwas lückenhaften Pseudocode erstellt. Verstehst du meine Frage?

Code: Alles auswählen

...
def __init__(self, max):
    ...

def __iter__(self):
    return self

def __next__(self):
    if self.n <= self.max #ich meine in dieser Zeile statt ein self.max etwas mit len()
    ...
"Those who can imagine anything, can create the impossible." Alan Turing
Sirius3
User
Beiträge: 14998
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 18. Juni 2021, 10:18

Einen StopIteration-Error sieht man normalerweise gar nicht, weil der z.B. direkt bei einer for-Schleife intern abgefangen wird.
Für viele Iteratoren kann man gar keine Länge angeben, weil nicht von Anfang an klar ist, wie viele Elemente es gibt.
Antworten