Was ist der Unterschied zwischen Iteratoren und Generatoren? Einige Beispiele, wann Sie jeden Fall verwenden würden, wären hilfreich.
iterator
ist ein allgemeineres Konzept: Jedes Objekt, dessen Klasse eine next
Methode ( __next__
in Python 3) und eine __iter__
Methode hat, die dies tut return self
.
Jeder Generator ist ein Iterator, aber nicht umgekehrt. Ein Generator wird durch Aufrufen einer Funktion erstellt, die einen oder mehrere yield
Ausdrücke enthält ( yield
Anweisungen in Python 2.5 und früheren Versionen) und ein Objekt ist, das der Definition von a im vorherigen Absatz entspricht iterator
.
Möglicherweise möchten Sie einen benutzerdefinierten Iterator anstelle eines Generators verwenden, wenn Sie eine Klasse mit einem etwas komplexen Verhalten zur Aufrechterhaltung des Zustands benötigen oder andere Methoden als next
(und __iter__
und __init__
) verfügbar machen möchten . Meistens ein Generator (manchmal für hinreichend einfache Bedürfnisse, ein Generator Ausdruck ) ist ausreichend, und es ist einfacher Code , weil Zustand Wartung (in Grenzen) ist im Grunde „für Sie getan“ durch den Rahmen aufgehängt zu werden und wieder aufgenommen.
Zum Beispiel ein Generator wie:
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
oder der äquivalente Generatorausdruck (genexp)
generator = (i*i for i in range(a, b))
würde mehr Code benötigen, um als benutzerdefinierter Iterator erstellt zu werden:
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self): return self
def next(self): # __next__ in Python 3
if self.start >= self.stop:
raise StopIteration
current = self.start * self.start
self.start += 1
return current
iterator = Squares(a, b)
Aber natürlich können Sie mit dem Unterricht Squares
leicht zusätzliche Methoden anbieten, z
def current(self):
return self.start
wenn Sie tatsächlich solche zusätzlichen Funktionen in Ihrer Anwendung benötigen.
for ... in ...:
einer Funktion sein, an eine Funktion übergeben, oder Sie rufen aniter.next()
for..in
Syntax zu verwenden, ein Fehler aufgetreten ist . Vielleicht hat mir etwas gefehlt, aber es ist einige Zeit her, ich erinnere mich nicht, ob ich es gelöst habe. Vielen Dank!Zusammenfassend: Iteratoren sind Objekte mit einem
__iter__
und einem__next__
(next
in Python 2) Methode. Generatoren bieten eine einfache, integrierte Möglichkeit, Instanzen von Iteratoren zu erstellen.Eine Funktion mit Yield darin ist immer noch eine Funktion, die beim Aufruf eine Instanz eines Generatorobjekts zurückgibt:
Ein Generatorausdruck gibt auch einen Generator zurück:
Lesen Sie weiter, um eine ausführlichere Darstellung und Beispiele zu erhalten.
Ein Generator ist ein Iterator
Insbesondere ist der Generator ein Subtyp des Iterators.
Wir können einen Generator auf verschiedene Arten erstellen. Ein sehr häufiger und einfacher Weg, dies zu tun, ist eine Funktion.
Insbesondere ist eine Funktion mit Ausbeute eine Funktion, die beim Aufruf einen Generator zurückgibt:
Und ein Generator ist wieder ein Iterator:
Ein Iterator ist ein Iterator
Ein Iterator ist ein Iterator,
__iter__
Dies erfordert eine Methode, die einen Iterator zurückgibt:Einige Beispiele für Iterables sind die integrierten Tupel, Listen, Wörterbücher, Mengen, eingefrorenen Mengen, Zeichenfolgen, Byte-Zeichenfolgen, Byte-Arrays, Bereiche und Speicheransichten:
Iteratoren erfordern ein
next
oder__next__
MethodeIn Python 2:
Und in Python 3:
Wir können die Iteratoren von den eingebauten Objekten (oder benutzerdefinierten Objekten) mit der folgenden
iter
Funktion abrufen:Die
__iter__
Methode wird aufgerufen, wenn Sie versuchen, ein Objekt mit einer for-Schleife zu verwenden. Dann wird die__next__
Methode für das Iteratorobjekt aufgerufen, um jedes Element für die Schleife herauszuholen. Der Iterator wird ausgelöst,StopIteration
wenn Sie ihn erschöpft haben, und er kann zu diesem Zeitpunkt nicht wiederverwendet werden.Aus der Dokumentation
Aus dem Abschnitt "Generatortypen" des Abschnitts "Iteratortypen" der Dokumentation zu integrierten Typen :
(Betonung hinzugefügt.)
Daraus lernen wir, dass Generatoren eine (bequeme) Art von Iterator sind.
Beispiel für Iteratorobjekte
Sie können ein Objekt erstellen, das das Iterator-Protokoll implementiert, indem Sie ein eigenes Objekt erstellen oder erweitern.
Es ist jedoch einfacher, einfach einen Generator zu verwenden, um dies zu tun:
Oder vielleicht einfacher, ein Generatorausdruck (funktioniert ähnlich wie Listenverständnisse):
Sie können alle auf die gleiche Weise verwendet werden:
Fazit
Sie können das Iterator-Protokoll direkt verwenden, wenn Sie ein Python-Objekt als ein Objekt erweitern müssen, über das iteriert werden kann.
In den allermeisten Fällen können Sie jedoch am besten
yield
eine Funktion definieren, die einen Generator-Iterator zurückgibt, oder Generator-Ausdrücke berücksichtigen.Beachten Sie schließlich, dass Generatoren als Coroutinen noch mehr Funktionen bieten. Ich erkläre Generatoren zusammen mit der
yield
Aussage ausführlich in meiner Antwort auf "Was macht das Schlüsselwort" Yield "?".quelle
Iteratoren:
Iterator sind Objekte, die verwendet werden
next()
Methode verwenden, um den nächsten Wert der Sequenz zu erhalten.Generatoren:
Ein Generator ist eine Funktion, die mit eine Folge von Werten erzeugt oder liefert
yield
Methode .Jeder
next()
Methodenaufruf für das Generatorobjekt (z.f
B. wie im folgenden Beispiel), der von der Generatorfunktion zurückgegeben wird (z.foo()
B. Funktion im folgenden Beispiel), generiert den nächsten Wert nacheinander.Wenn eine Generatorfunktion aufgerufen wird, gibt sie ein Generatorobjekt zurück, ohne mit der Ausführung der Funktion zu beginnen. Wann
next()
Methode zum ersten Mal aufgerufen wird, wird die Funktion ausgeführt, bis sie die Yield-Anweisung erreicht, die den Yield-Wert zurückgibt. Die Ausbeute verfolgt, dh erinnert sich an die letzte Ausführung. Der zweitenext()
Aufruf wird vom vorherigen Wert fortgesetzt.Das folgende Beispiel zeigt das Zusammenspiel zwischen Ausbeute und Aufruf der nächsten Methode für das Generatorobjekt.
quelle
Hinzufügen einer Antwort, da keine der vorhandenen Antworten speziell die Verwirrung in der offiziellen Literatur anspricht.
Generatorfunktionen sind gewöhnliche Funktionen, die mit
yield
anstelle vondefiniert werdenreturn
. Beim Aufruf gibt eine Generatorfunktion ein Generatorobjekt zurück , das eine Art Iterator ist - es hat einenext()
Methode. Wenn du anrufstnext()
, wird der nächste von der Generatorfunktion ausgegebene Wert zurückgegeben.Je nachdem, welches Python-Quelldokument Sie lesen, kann entweder die Funktion oder das Objekt als "Generator" bezeichnet werden. Das Python-Glossar besagt, dass Generatorfunktionen vorhanden sind, während das Python-Wiki Generatorobjekte impliziert. Das Python-Tutorial schafft es bemerkenswerterweise, beide Verwendungen innerhalb von drei Sätzen zu implizieren :
Die ersten beiden Sätze identifizieren Generatoren mit Generatorfunktionen, während der dritte Satz sie mit Generatorobjekten identifiziert.
Trotz all dieser Verwirrung kann man die Python-Sprachreferenz für das klare und endgültige Wort suchen :
In der formalen und präzisen Verwendung bedeutet "Generator" unqualifiziert also Generatorobjekt, nicht Generatorfunktion.
Die obigen Referenzen gelten für Python 2, aber die Python 3-Sprachreferenz sagt dasselbe. Das Python 3-Glossar besagt dies jedoch
quelle
Jeder hat eine wirklich nette und ausführliche Antwort mit Beispielen und ich schätze es sehr. Ich wollte nur ein paar kurze Antworten für Leute geben, die konzeptionell noch nicht ganz klar sind:
Wenn Sie Ihren eigenen Iterator erstellen, ist dies ein wenig kompliziert - Sie müssen eine Klasse erstellen und mindestens den Iter und die nächsten Methoden implementieren. Aber was ist, wenn Sie diesen Aufwand nicht durchlaufen und schnell einen Iterator erstellen möchten? Glücklicherweise bietet Python eine Abkürzung zum Definieren eines Iterators. Alles, was Sie tun müssen, ist, eine Funktion mit mindestens 1 Aufruf zu definieren. Wenn Sie diese Funktion aufrufen, gibt sie " etwas " zurück, das sich wie ein Iterator verhält (Sie können die nächste Methode aufrufen und in einer for-Schleife verwenden). Das etwas hat in Python einen Namen namens Generator
Hoffe das klärt ein bisschen.
quelle
In früheren Antworten wurde dieser Zusatz übersehen: Ein Generator verfügt über eine
close
Methode, typische Iteratoren dagegen nicht. Dieclose
Methode löstStopIteration
im Generator eine Ausnahme aus, die in a abgefangen werden kannfinally
Klausel in diesem Iterator enthalten ist, um die Möglichkeit zu erhalten, eine Bereinigung auszuführen. Diese Abstraktion macht es am nützlichsten in großen als einfachen Iteratoren. Man kann einen Generator schließen, wie man eine Datei schließen könnte, ohne sich darum kümmern zu müssen, was darunter liegt.Meine persönliche Antwort auf die erste Frage wäre jedoch: iteratable hat nur eine
__iter__
Methode, typische Iteratoren haben nur eine__next__
Methode, Generatoren haben sowohl eine__iter__
als auch eine__next__
und eine zusätzlicheclose
.Für die zweite Frage wäre meine persönliche Antwort: In einer öffentlichen Schnittstelle tendiere ich dazu, Generatoren sehr zu bevorzugen, da sie widerstandsfähiger sind: die
close
Methode eine größere Kompositionsfähigkeit mityield from
. Vor Ort kann ich Iteratoren verwenden, aber nur, wenn es sich um eine flache und einfache Struktur handelt (Iteratoren lassen sich nicht leicht zusammensetzen) und wenn Grund zu der Annahme besteht, dass die Sequenz ziemlich kurz ist, insbesondere wenn sie vor dem Ende gestoppt werden kann. Ich neige dazu, Iteratoren als ein Grundelement niedriger Ebene zu betrachten, außer als Literale.Generatoren sind für Kontrollflussfragen ein ebenso wichtiges Konzept wie Versprechen: Beide sind abstrakt und zusammensetzbar.
quelle
__iter__
Wie kommt es, dass ein Iterator__next__
nur eine Methode haben kann, da er eine Methode hat ? Wenn sie iterabel sein sollen, würde ich erwarten, dass sie notwendigerweise auch haben__iter__
.__iter__
on iterables, um einen Iterator zurückzugeben, für den nur einenext
Methode erforderlich ist (__next__
in Python3). Bitte verwechseln Sie Standards (für die Eingabe von Enten) nicht mit ihrer Implementierung (wie ein bestimmter Python-Interpreter sie implementiert hat). Dies ist ein bisschen wie die Verwechslung zwischen Generatorfunktionen (Definition) und Generatorobjekten (Implementierung). ;)Eine Generatorfunktion ist wie eine reguläre Funktion in Python, enthält jedoch eine oder mehrere
yield
Anweisungen. Generatorfunktionen sind ein großartiges Werkzeug, um Iteratorobjekte so einfach wie möglich zu erstellen . Das durch die Generatorfunktion zurückgegebene Iteratorobjekt wird auch als Generatorobjekt oder Generator bezeichnet .In diesem Beispiel habe ich eine Generatorfunktion erstellt, die ein Generatorobjekt zurückgibt
<generator object fib at 0x01342480>
. Genau wie andere Iteratoren können Generatorobjekte in einerfor
Schleife oder mit der integrierten Funktion verwendet werden,next()
die den nächsten Wert vom Generator zurückgibt.Eine Generatorfunktion ist daher der einfachste Weg, ein Iterator-Objekt zu erstellen.
Jedes Generatorobjekt ist ein Iterator, aber nicht umgekehrt. Ein benutzerdefiniertes Iteratorobjekt kann erstellt werden, wenn seine Klasse eine Methode
__iter__
und eine__next__
Methode implementiert (auch als Iteratorprotokoll bezeichnet).Es ist jedoch viel einfacher, die Generatorfunktion zum Erstellen von Iteratoren zu verwenden, da diese ihre Erstellung vereinfachen. Ein benutzerdefinierter Iterator bietet Ihnen jedoch mehr Freiheit und Sie können auch andere Methoden gemäß Ihren Anforderungen implementieren, wie im folgenden Beispiel gezeigt.
quelle
Beispiele von Ned Batchelder werden für Iteratoren und Generatoren dringend empfohlen
Eine Methode ohne Generatoren, die gerade Zahlen macht
während mit einem Generator
return
ErklärungDas Aufrufen der
evens
Methode (Generator) ist wie gewohntIterator
und dieses Lesezeichen hat nichts zu tun, außer sich zu bewegen
next
Um Generator zu benutzen ... brauchen wir eine Funktion
Um Iterator zu benutzen ... brauchen wir
next
unditer
Wie gesagt:
Der ganze Nutzen von Iterator:
quelle
Sie können beide Ansätze für dieselben Daten vergleichen:
Wenn Sie den Speicherbedarf überprüfen, benötigt der Generator außerdem viel weniger Speicher, da nicht alle Werte gleichzeitig im Speicher gespeichert werden müssen.
quelle
Ich schreibe auf sehr einfache Weise speziell für Python-Neulinge, obwohl Python im Grunde so viele Dinge tut.
Beginnen wir mit dem Grundlegenden:
Betrachten Sie eine Liste,
Schreiben wir eine äquivalente Funktion:
o / p von
print(l): [1,2,3]
& o / p vonprint(f()) : [1,2,3]
Lassen Sie uns die Liste iterierbar machen: In Python ist die Liste immer iterierbar, dh Sie können den Iterator jederzeit anwenden.
Wenden wir den Iterator auf die Liste an:
Lassen Sie uns eine Funktion iterierbar machen, dh eine äquivalente Generatorfunktion schreiben. In Python, sobald Sie das Schlüsselwort eingeben
yield
; Es wird eine Generatorfunktion und der Iterator wird implizit angewendet.Hinweis: Jeder Generator ist immer iterierbar, wenn der implizite Iterator angewendet wird. Hier ist der implizite Iterator der springende Punkt. Die Generatorfunktion lautet also:
Wenn Sie also beobachtet haben, sobald Sie die Funktion eines Generators erstellt haben, ist dies bereits iter (f).
Jetzt,
Es ist irgendwie so, dass Sie int in int (x) umwandeln, das bereits int ist und int (x) bleibt.
Zum Beispiel o / p von:
ist
Vergiss niemals, dass dies Python ist und nicht C oder C ++
Daher lautet die Schlussfolgerung aus der obigen Erklärung:
quelle