Was ist die "Ausbeute" Stichwort?
Was ist der nutzen der yield
Schlüsselwort in Python? Was tut es?
Zum Beispiel, versuche ich zu verstehen, diesen code1:
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
- Und dies ist der Anrufer:
result, candidates = [], [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
Was passiert, wenn die Methode _get_child_candidates
genannt wird?
Wird eine Liste zurückgegeben? Ein einzelnes element? Heißt das nochmal? Wann werden nachfolgende Anrufe stoppen?
1. Dieses Stück code wurde geschrieben von Jochen Schulz (jrschulz), die aus einer großen Python-Bibliothek für Metrische Räume. Dies ist der link zum kompletten Quelle: Modul mspace.
InformationsquelleAutor Alex. S. | 2008-10-23
Du musst angemeldet sein, um einen Kommentar abzugeben.
Zu verstehen, was
yield
funktioniert, müssen Sie verstehen, was Generatoren sind. Und bevor Sie verstehen können, Generatoren, müssen Sie verstehen iterables.Iterables
Wenn Sie eine Liste erstellen, können Sie Lesen Sie die Elemente nacheinander. Die Lektüre seiner Elemente nacheinander aufgerufen iteration:
mylist
ist ein iterierbar. Wenn Sie eine Liste verwenden, Verständnis, erstellen Sie eine Liste, und so durchsuchbar:Alles, was Sie können "
for... in...
", ist eine der iterierbar;lists
,strings
Dateien...Diese iterables sind praktisch, da Sie Sie Lesen kann, so viel wie Sie wollen, aber Sie speichern alle Werte im Speicher, und dies ist nicht immer, was Sie wollen, wenn Sie haben eine Menge von Werten.
Generatoren
Generatoren Iteratoren, eine Art durchsuchbar können Sie nur Durchlaufen, sobald. Generatoren nicht speichern aller Werte im Speicher, , die Sie generieren, werden die Werte on-the-fly:
Ist es genau das gleiche, außer Sie verwendet
()
statt[]
. ABER Sie nicht durchführenfor i in mygenerator
ein zweites mal, da die Erzeuger können nur einmal verwendet werden: berechnen Sie 0 ist, dann vergessen Sie es und berechnen 1, - und end-Berechnung 4, eins nach dem anderen.Ertrag
yield
ist ein Schlüsselwort, das verwendet wird, wiereturn
, außer die Funktion gibt einen generator.Hier ist es ein nutzloses Beispiel, aber es ist praktisch, wenn Sie wissen, dass Ihre Funktion gibt eine riesige Menge von Werten, Sie müssen nur einmal gelesen werden.
Master
yield
müssen Sie verstehen, dass wenn Sie die Funktion aufrufen, den code, den Sie geschrieben haben, im Hauptteil der Funktion nicht ausgeführt. Die Funktion gibt nur die generator-Objekt, das ist ein bisschen tricky 🙂Dann, Ihr code wird weiterhin von wo es aufgehört hat jedes mal
for
verwendet der generator.Jetzt der schwierige Teil:
Ersten mal die
for
ruft der generator-Objekt erstellt aus Ihrer Funktion führen Sie den code in Ihrer Funktion von den Anfängen bis es trifftyield
, dann werde zurückkehren den ersten Wert aus der Schleife. Dann, jeder weitere Anruf wird ausgeführt, die Schleife, die Sie geschrieben haben in die Funktion ein weiteres mal, und kehren Sie den nächsten Wert, bis es kein Wert zurückgeben.Der generator gilt als leer, sobald die Funktion läuft, aber nicht trifft
yield
mehr. Es kann sein, weil die Schleife hatte zu einem Ende kommen, oder weil Sie nicht erfüllen, eine"if/else"
mehr.Dein code erklärt
Generator:
Anrufer:
Dieser code enthält einige smart parts:
Die Schleife iteriert über eine Liste, aber die Liste erweitert, während die Schleife wird Durchlaufen 🙂 Es ist ein prägnant Weg zu gehen durch alle diese verschachtelten Daten, auch wenn es ein bisschen gefährlich, da können Sie am Ende mit einer unendlichen Schleife. In diesem Fall
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
erschöpft alle Werte des Generators, aberwhile
hält die Schaffung neuer generator-Objekte zu erstellen, die unterschiedliche Werte von den vorherigen, da Sie nicht angewendet, die auf demselben Knoten.Den
extend()
Methode ist ein list-Objekt-Methode, die erwartet, dass ein durchsuchbar und fügt seine Werte in die Liste.In der Regel passieren wir eine Liste:
Aber in deinem code wird es einen generator an, der ist gut, weil:
Und es funktioniert, weil Python nicht darum, ob das argument der Methode ist eine Liste oder nicht. Python erwartet iterables so funktioniert es mit strings, Listen, Tupeln und Generatoren! Dies wird als duck typing und ist einer der Gründe, warum Python ist so cool. Aber das ist eine andere Geschichte, eine andere Frage...
Können Sie hier aufhören, oder Lesen Sie ein wenig, um zu sehen, eine erweiterte Verwendung von einem generator:
Controlling a generator Erschöpfung
Hinweis: Für Python 3 verwenden Sie
print(corner_street_atm.__next__())
oderprint(next(corner_street_atm))
Kann es sinnvoll sein, für verschiedene Dinge wie die Steuerung des Zugriffs auf eine Ressource.
Itertools, Ihre beste Freundin
Dem itertools-Modul enthält spezielle Funktionen zum Bearbeiten von iterables. Immer verdoppeln möchten, einen generator?
Kette zwei Generatoren? Gruppe von Werten in einer verschachtelten Liste mit einem one-liner?
Map /Zip
ohne die Schaffung einer anderen Liste?Dann nur
import itertools
.Beispiel? Lassen Sie uns sehen, die mögliche Ordnungen der Ankunft für eine vier-Pferderennen:
Verständnis der inneren Mechanismen der iteration
Iteration ist ein Prozess impliziert iterables (Umsetzung der
__iter__()
- Methode) und Iteratoren (Umsetzung der__next__()
- Methode).Iterables sind alle Objekte, die Sie bekommen können, einen iterator aus. Iteratoren sind Objekte, mit denen Sie umzusetzen, iterables.
Gibt es mehr darüber in diesem Artikel über wie
for
- Schleifen arbeiten.iter()
auf jeden wiederholenden Objekt, und versuchen Sie zur Iteration über das Ergebnis mehr als einmal.Sie haben Ihre Begriffe Durcheinander. Ein iterierbar ist etwas mit einem
__iter__
Methode. Ein iterator ist das Ergebnis des Aufrufsiter()
auf ein durchsuchbar. Iteratoren kann nur Durchlaufen werden, wenn.yield
ist nicht als magisch, diese Antwort suggeriert. Wenn Sie eine Funktion aufrufen, enthält eineyield
- Anweisung überall, Sie bekommen ein generator-Objekt, aber kein code ausgeführt wird. Dann jedes mal, wenn Sie ein Objekt extrahieren aus dem generator, Python führt code in der Funktion, bis es kommt zu eineryield
Anweisung, pausiert dann und liefert das Objekt. Wenn Sie extrahieren ein anderes Objekt, Python Bewerbungen nur nach deryield
und wird fortgesetzt, bis es erreicht einen weiterenyield
(oft die gleichen, aber eine iteration später). Dies wird fortgesetzt, bis die Funktion läuft das Ende, an welchem Punkt der generator gilt als erschöpft."Diese iterables sind praktisch... aber Sie speichern alle Werte im Speicher, und dies ist nicht immer, was Sie wollen", ist entweder falsch oder verwirrend. Ein iterierbar gibt einen iterator bei Aufruf von iter() auf die iterierbar, und ein iterator muss nicht immer zum speichern von Werten im Speicher, abhängig von der Implementierung des iter - Methode, kann es auch erzeugen, Werte in der Sequenz auf Nachfrage.
InformationsquelleAutor e-satis
Verknüpfung zu verstehen
yield
Sind, wenn Sie eine Funktion mit
yield
Aussagen, gilt dieser einfache trick, um zu verstehen, was passieren wird:result = []
am Anfang der Funktion.yield expr
mitresult.append(expr)
.return result
an der Unterseite der Funktion.yield
Aussagen! Lesen und herausfinden, code.Dieser trick kann Ihnen eine Idee geben, die Logik hinter der Funktion, aber was passiert eigentlich mit
yield
deutlich von dem unterscheiden, was passiert in der Liste basierten Ansatz. In vielen Fällen wird die Ausbeute Ansatz wird viel mehr Speicher effizienter und schneller zu. In anderen Fällen wird dieser trick bekommen Sie stecken in einer Endlosschleife, obwohl die ursprüngliche Funktion funktioniert Prima. Lesen Sie weiter, um mehr zu erfahren...Nicht zu verwechseln Ihr Iterables, Iteratoren und Generatoren
Erste, der iterator-Protokoll - wenn Sie schreiben
Python führt die folgenden zwei Schritte:
Bekommt einen iterator für
mylist
:Call
iter(mylist)
-> diese gibt ein Objekt zurück, mit einemnext()
Methode (oder__next__()
in Python 3).[Dies ist der Schritt, die meisten Leute vergessen, Ihnen zu sagen, über]
Nutzt den iterator zum Durchlaufen der Elemente:
Halten, ruft die
next()
Methode auf dem iterator zurück von Schritt 1. Der Rückgabewert vonnext()
zugeordnet istx
und der schleifenrumpf wird ausgeführt. Wenn eine AusnahmeStopIteration
wird ausgelöst von innerhalbnext()
es bedeutet, es gibt keine Werte mehr in der "iterator" und die Schleife beendet wird.Die Wahrheit ist Python führt die beiden oben genannten Schritte, Wann immer es will Schleife über den Inhalt eines Objekt - so könnte es sein, eine for-Schleife, aber es könnte auch sein code wie
otherlist.extend(mylist)
(wootherlist
ist eine Python-Liste).Hier
mylist
ist ein iterierbar, denn es implementiert das iterator-Protokoll. In einer benutzerdefinierten Klasse implementieren Sie die__iter__()
Methode, um Instanzen Ihrer Klasse iterierbar. Diese Methode soll zurückgeben eine iterator. Ein iterator ist ein Objekt mit einernext()
Methode. Es ist möglich, beide implementieren__iter__()
undnext()
auf die gleiche Klasse und haben__iter__()
zurückself
. Dies funktioniert für einfache Fälle, aber nicht, wenn Sie zwei Iteratoren Durchlaufen das gleiche Objekt zur gleichen Zeit.So, dass die das iterator-Protokoll, viele Objekte, die dieses Protokoll implementieren:
__iter__()
.Beachten Sie, dass eine
for
Schleife nicht wissen, welche Art von Objekt es zu tun haben - es folgt einfach der iterator-Protokoll, und ist glücklich, Element nach Element, wie es fordertnext()
. Built-in Listen zurückgeben, deren Elemente eins nach dem anderen, Wörterbücher Rückkehr der Schlüssel nacheinander die Dateien zurückkehren, die Linien eins nach dem anderen, etc. Generatoren und zurück... gut, dass ' s, woyield
:Statt
yield
Aussagen, wenn Sie hatte dreireturn
Aussagen inf123()
würde nur das erste ausgeführt, und würde die Funktion beenden. Aberf123()
ist keine gewöhnliche Funktion. Wennf123()
heißt, es nicht wieder die Werte in den yield-Anweisungen! Es gibt ein generator-Objekt. Auch die Funktion nicht wirklich verlassen - geht es in einem angehaltenen Zustand. Wenn diefor
Schleife versucht, um eine Schleife über dem generator-Objekt, die Funktion wird fortgesetzt, von seinen abgehängten Zustand in der nächsten Zeile nach deryield
es zuvor wieder aus, führt die nächste Zeile des Codes, in diesem Fall einyield
- Anweisung zurück, die als der nächste Punkt. Dies geschieht solange, bis die Funktion beendet wird, an welcher Stelle der generator wirftStopIteration
, und die Schleife wird beendet.So die generator-Objekt ist so in der Art wie ein adapter - an einem Ende weist es das iterator-Protokoll, indem Sie
__iter__()
undnext()
Methoden zu halten, diefor
Schleife glücklich. Am anderen Ende jedoch, es wird die Funktion ausgeführt, gerade genug, um den nächsten Wert aus ihm heraus, und legt es zurück in Ruhezustand befindet.Warum Die Verwendung Von Generatoren?
In der Regel können Sie code schreiben, der keine Generatoren, sondern implementiert die gleiche Logik. Eine option ist die temporäre Liste "trick", den ich vorher erwähnte. Das wird nicht in allen Fällen funktionieren, z.B. wenn Sie Endlosschleifen, oder es kann zu einer ineffizienten Nutzung von Speicher, wenn Sie haben eine wirklich lange Liste. Der andere Ansatz ist die Implementierung einer neuen iterierbar Klasse
SomethingIter
hält Zustand in Instanz-Membern und führt der nächste logische Schritt, es istnext()
(oder__next__()
in Python 3) Methode. Abhängig von der Logik, wird der code innerhalb dernext()
Methode kann am Ende der Suche sehr Komplex und anfällig für Fehler. Hier Generatoren bieten eine saubere und einfache Lösung.send
in einen generator, der ein großer Teil der point-of-Generatoren?"es könnte eine for-Schleife, aber es könnte auch sein code wie
otherlist.extend(mylist)
" -> Das ist falsch.extend()
ändert die Liste in-place und nicht wieder ein durchsuchbar. Versuchen, um eine Schleife überotherlist.extend(mylist)
fehl mitTypeError
weilextend()
implizit zurückNone
, und man kann nicht DurchlaufenNone
.Hast du falsch verstanden, der Satz. Es bedeutet, dass python-führt die zwei genannten Schritte auf
mylist
(nicht aufotherlist
) bei der Ausführungotherlist.extend(mylist)
.InformationsquelleAutor user28409
Denken Sie an es auf diese Weise:
Ein iterator ist ein schicker klingenden Begriff für ein Objekt, das eine
next()
Methode. So eine Ausbeute-ed-Funktion endet als so etwas wie dieses:Original version:
Dies ist im Grunde das, was der Python-interpreter nicht mit dem obigen code:
Für mehr Einblick, was hinter den kulissen geschieht, die
for
- Schleife umgeschrieben werden kann zu:Macht das mehr Sinn machen, oder nur verwirren Sie mehr? 🙂
Sollte ich beachten Sie, dass diese ist eine starke Vereinfachung der Veranschaulichung. 🙂
__getitem__
definiert werden könnte statt__iter__
. Zum Beispiel:class it: pass; it.__getitem__ = lambda self, i: i*10 if i < 10 else [][0]; for i in it(): print(i)
werden, Es wird gedruckt: 0, 10, 20, ..., 90Ich habe versucht das Beispiel in Python 3.6 und wenn ich
iterator = some_function()
die variableiterator
nicht über eine Funktion namensnext()
mehr, sondern nur noch eine__next__()
Funktion. Dachte, ich hätte es erwähnen.InformationsquelleAutor Jason Baker
Den
yield
Schlüsselwort ist reduziert auf zwei einfachen Tatsachen:yield
Stichwort überall innerhalb einer Funktion, wird die Funktion nicht mehr zurück über diereturn
- Anweisung. Statt, es sofort gibt eine faul "pending-Liste" Objekt genannt einen generatorlist
oderset
oderrange
oder dict-Ansicht, mit einem built-in-Protokoll für den Besuch jedes element in einer bestimmten Reihenfolge.Kurz gesagt: ein generator ist ein fauler, inkrementell-pending Liste, und
yield
- Anweisungen ermöglichen die Verwendung einer Funktion notation, um das Programm der Liste Werte der generator sollte schrittweise spucken.Beispiel
Definieren wir nun eine Funktion
makeRange
das ist genau wie Python -range
. AufrufmakeRange(n)
GIBT EINEN GENERATOR:Zu zwingen, wird der generator sofort wieder seine ausstehenden Werte, die Sie übergeben können, es in
list()
(wie könnten Sie alle durchsuchbar):Vergleich etwa zum "einfach wieder eine Liste"
Obigen Beispiel kann gedacht werden als nur das erstellen einer Liste aus, die Sie anfügen und zurück:
Gibt es einen großen Unterschied, obwohl, finden Sie im letzten Abschnitt.
, Wie Sie möglicherweise verwenden Generatoren
Einer iterierbar ist der Letzte Teil einer Liste Verständnis, und alle Generatoren sind durchsuchbar, so dass Sie oft benutzt, etwa so:
Um ein besseres Gefühl für Generatoren, Sie können spielen, um mit der
itertools
Modul (verwenden Siechain.from_iterable
eher alschain
wenn gerechtfertigt). Zum Beispiel könnten Sie sogar Generatoren zu implementieren unendlich langen lazy Listen wieitertools.count()
. Sie könnten setzen Sie Ihre eigenedef enumerate(iterable): zip(count(), iterable)
oder alternativ dazu mit deryield
keyword in eine while-Schleife.Bitte beachten Sie: die Generatoren können tatsächlich verwendet werden, für viele weitere Dinge, wie Implementierung von Coroutinen oder nicht-deterministische Programmierung oder andere elegante Sachen. Jedoch, die "lazy lists" Sicht, die ich hier vorstellen ist die häufigste Verwendung finden Sie.
Hinter den kulissen
Dies ist, wie die "Python" iteration-Protokoll" funktioniert. Das ist, was passiert, wenn Sie
list(makeRange(5))
. Dies ist, was ich beschreiben, früher als "faul, inkrementelle Liste".Den built-in-Funktion
next()
ruft einfach nur die Objekte.next()
Funktion, die ein Teil der "iteration protocol" und ist auf alle Iteratoren. Sie können manuell verwenden dernext()
- Funktion (und andere Teile der iteration protocol) zu implementieren, die Lust auf Dinge, die in der Regel auf Kosten der Lesbarkeit, so versuchen zu vermeiden, tun,...Kleinigkeiten
Normalerweise würden die meisten Menschen kümmern sich nicht um die folgenden Auszeichnungen und wahrscheinlich wollen Sie hier aufhören zu Lesen.
In Python-sprechen, eine iterierbar ist ein Objekt, das "versteht das Konzept einer for-Schleife" wie eine Liste
[1,2,3]
, und ein iterator ist eine bestimmte Instanz des angeforderten for-Schleife wie[1,2,3].__iter__()
. Ein generator ist genau das gleiche wie jede iterator, außer für die Art, wie es geschrieben wurde (mit Funktion syntax).Wenn Sie Anfrage ein iterator aus einer Liste, es erzeugt einen neuen iterator. Allerdings, wenn Sie einen iterator vom iterator (was Sie selten tun), man erhält nur eine Kopie von sich selbst.
So, in dem unwahrscheinlichen Fall, dass Sie scheitern, so etwas zu tun...
... dann denken Sie daran, dass ein generator ist ein iterator; das heißt, es ist ein-Zeit-verwenden. Wenn Sie wiederverwenden möchten, sollten Sie rufen
myRange(...)
wieder. Wenn Sie brauchen, um das Ergebnis verwenden, zweimal, konvertieren Sie das Ergebnis in einer Liste und speichern Sie in einer Variablenx = list(myRange(5))
. Diejenigen, die unbedingt brauchen, um Klon-generator (zum Beispiel, die machen erschreckend hackish metaprogramming) könnenitertools.tee
wenn absolut notwendig, da die kopierbaren iterator Python PEP standards Vorschlag wurde zurückgestellt werden.InformationsquelleAutor ninjagecko
Beantworten Gliederung/Inhaltsangabe
Ertrag
, wenn Sie aufgerufen werden, gibt eine Generator.yield from
.return
in einem generator.)Generatoren:
yield
ist nur zulässig innerhalb einer Funktionsdefinition, und die Einbeziehung vonyield
in die definition einer Funktion macht es wieder einen generator an.Die Idee für Generatoren kommt aus anderen Sprachen (siehe Fußnote 1) mit unterschiedlichen Implementierungen. In Python Generatoren, die die Ausführung des Codes ist eingefroren an der Stelle, von der Ausbeute. Wenn der generator aufgerufen wird (Methoden werden weiter unten erläutert), die Ausführung und dann friert bei der nächsten yield.
yield
bietet eineeinfach Weg von die Implementierung der iterator-Protokoll, definiert durch die folgenden zwei Methoden:
__iter__
undnext
(Python 2) oder__next__
(Python 3). Diese beiden Methodenein Objekt einen iterator, könnten Sie Typ-check mit der
Iterator
Abstrakte BasisklasseKlasse aus der
collections
Modul.Den generator-Typ ist ein Subtyp des Datentyps iterator:
Und, wenn nötig, können wir Typ-überprüfung wie diese:
Eine Funktion eines
Iterator
ist, dass einmal erschöpft, können Sie nicht wiederverwenden, oder es zurücksetzen:Musst du anderes machen, wenn Sie wollen, zu verwenden, seine Funktionalität wieder (siehe Fußnote 2):
Kann man die Ertragsdaten programmgesteuert, beispielsweise:
Den oben genannten einfachen generator entspricht auch der unter - wie der Python 3.3 (und nicht in Python 2), die Sie verwenden können,
Ertrag
:Jedoch
yield from
ermöglicht auch die delegation subgenerators,das wird im folgenden Abschnitt erläutert auf kooperative delegation mit sub-Coroutinen.
Coroutinen:
yield
Formen einen Ausdruck, der es erlaubt, Daten an den generator (siehe Fußnote 3)Hier ist ein Beispiel, beachten Sie die
received
variable, die die Daten, die gesendet wird, um den generator:Zuerst müssen wir Schlange der generator mit der builtin-Funktion,
next
. Es wirdrufen Sie die entsprechende
next
oder__next__
Methode, abhängig von der version derPython:
Und jetzt können wir das senden von Daten in den generator. (Senden
None
das gleiche wie der Aufruf von
next
.) :Genossenschaft Delegation, Sub-Koroutine mit
yield from
Nun, daran erinnern, dass
yield from
ist in Python 3. Dies ermöglicht es uns zu delegierenCoroutinen zu einem subcoroutine:
Und jetzt können wir das delegieren von Funktionalität zu einem sub-generator, und es kann verwendet werden,
durch einen generator-nur wie oben:
Lesen Sie mehr über die präzise Semantik von
yield from
im PEP 380.Anderen Methoden: schließen und werfen
Den
close
- Methode löstGeneratorExit
an dem Punkt der Funktiondie Ausführung war gefroren. Diese wird auch aufgerufen werden, indem Sie
__del__
so dass Siekönnen alle cleanup-code, wo Sie behandeln die
GeneratorExit
:Können Sie auch werfen eine exception, die behandelt werden können, in den generator
oder propagiert zurück an den Benutzer:
Abschluss
Ich glaube, ich habe alle Gesichtspunkte, die folgende Frage:
Es stellt sich heraus, dass
yield
nicht viel. Ich bin sicher, ich könnte noch mehrGründliche Beispiele. Wenn Sie mehr wollen oder haben einige Konstruktive Kritik, lasst es mich wissen durch Kommentare
unten.
Anhang:
Kritik von Oben/Akzeptierte Antwort**
__iter__
Methode zurückgeben iterator. Ein iterator bietet eine.next
(Python 2 oder.__next__
(Python 3) - Methode, die implizit genannt, indemfor
Schleifen, bis es wirftStopIteration
, und sobald es tut, wird es auch weiterhin tun.yield
Teil..next
Methode, wenn er stattdessen sollten die builtin-Funktionnext
. Es wäre eine entsprechende Dereferenzierung, weil sein code nicht funktioniert in Python 3.yield
nicht an alle.yield
bietet zusammen mit der neuen Funktionalitätyield from
in Python 3. Oben/akzeptierte Antwort ist eine sehr unvollständige Antwort.Kritik an der Antwort, die darauf hindeutet
yield
in einen generator-Ausdruck oder Verständnis.Die Grammatik erlaubt derzeit eines Ausdrucks in einer Liste erfassen.
Seit Ausbeute ist ein Ausdruck, es wurde angepriesen von einigen als interessant für die Nutzung in Verstehens-oder generator-Ausdruck - trotz der Anführungen kein besonders guter Anwendungsfall.
Den CPython-core-Entwickler sind diskutieren abwertend seine Zulage.
Hier ist ein relevanter Beitrag aus der mailing-Liste:
Weiter, es ist ein offene Frage (10544), die scheint zu sein, zeigt in die Richtung dieser nie eine gute Idee (PyPy, Python-Implementierung in Python geschrieben, ist bereits die Anhebung syntax Warnungen.)
Unteren Zeile, bis die Entwickler von CPython uns etwas anderes sagen: nicht setzen
yield
in einen generator-Ausdruck oder Verständnis.Die
return
- Anweisung in einem generatorIn Python 2:
Einer
expression_list
ist im Grunde eine beliebige Anzahl von Ausdrücken, die durch Komma getrennt - im wesentlichen in Python 2, stoppen Sie den generator mitreturn
, aber Sie können nicht einen Wert zurückgeben.In Python 3:
Fußnoten
Sprachen CLU, Sather, und das Symbol waren auf die in dem Vorschlag
Einführung das Konzept der Generatoren zu Python. Die Allgemeine Idee ist
dass eine Funktion aufrechterhalten kann, den internen Zustand und den Ertrag intermediate
Datenpunkte, die auf Nachfrage durch den Benutzer. Dieser versprach überlegen in der Leistung
auf andere Ansätze, einschließlich Python threading, die nicht auch verfügbar auf einigen Systemen.
Das bedeutet zum Beispiel, dass
xrange
Objekte (range
in Python 3) nichtIterator
s, obwohl Sie sind durchsuchbar, da Sie wiederverwendet werden können. Wie Listen, Ihre__iter__
Methoden zurück, iterator-Objekte.yield
wurde ursprünglich eingeführt, als eine Aussage, was bedeutet, dass eskonnte nur am Anfang einer Zeile in einem code-block.
Jetzt
yield
schafft eine Ausbeute Ausdruck.https://docs.python.org/2/reference/simple_stmts.html#grammar-token-yield_stmt
Diese änderung wurde vorgeschlagen, um es einem Benutzer erlauben, Daten zu senden, in den generator nur als
man könnte es erhalten haben. Um Daten zu senden, muss man in der Lage sein, ordnen Sie es mit etwas, und
für eine Aussage will einfach nicht funktionieren.
InformationsquelleAutor Aaron Hall
yield
ist wiereturn
- es gibt was auch immer Sie sagen, es (als generator). Der Unterschied ist, dass beim nächsten Aufruf des Generators, die Ausführung beginnt ab dem letzten Aufruf deryield
- Anweisung. Im Gegensatz zu zurück, der stack-frame wird nicht bereinigt, wenn Sie eine Rendite kommt, aber die Kontrolle übertragen wird, an den Aufrufer zurück, so dass Ihr Zustand wird fortgesetzt, das nächste mal die Funktion aufgerufen wird.In dem Fall von deinem code, die Funktion
get_child_candidates
benimmt sich wie ein iterator, so dass, wenn Sie erweitern Sie Ihre Liste, fügt ein element zu einem Zeitpunkt auf die neue Liste.list.extend
fordert einen iterator, bis es erschöpft ist. Im Fall von code-Beispiel, das Sie geschrieben, es wäre viel klarer, um einfach nur wieder ein Tupel und anfügen, dass auf der Liste.InformationsquelleAutor Douglas Mayle
Gibt ' s eine zusätzliche Sache zu erwähnen: eine Funktion, die Erträge tatsächlich nicht zur Kündigung. Ich habe code geschrieben wie diese:
Dann kann ich in anderen code wie folgt:
Es hilft wirklich vereinfachen einige Probleme, und macht einige Dinge einfacher, mit zu arbeiten.
InformationsquelleAutor Claudiu
Für diejenigen, die lieber ein minimal Beispiel arbeiten, meditieren Sie auf dieser interaktiven Python-session:
InformationsquelleAutor Daniel
TL;DR
Statt:
hierzu:
Wann immer Sie sich finden, bauen Sie eine Liste von Grund auf neu
yield
jedes Stück statt.Dies war mein erstes "aha" - moment mit der Ausbeute.
yield
ist ein zuckerhaltige Art und Weise zu sagenGleiche Verhalten:
Anderes Verhalten:
Ausbeute ist single-pass -: Sie können nur einmal Durchlaufen. Wenn eine Funktion hat, eine Rendite in der it nennen wir es generator Funktion. Und ein iterator ist, was es gibt. Diese Begriffe sind aufschlussreich. Wir verlieren den Komfort eines Containers, aber die Kraft gewinnen, eine Serie, die ist so berechnet, als nötig, und das beliebig lange.
Ausbeute ist faul, es bringt aus Berechnung. Eine Funktion mit einem Ertrag in es nicht tatsächlich ausgeführt, wenn Sie aufgerufen werden. Es gibt ein iterator-Objekt , merkt sich wo er aufgehört hat. Jedes mal, wenn Sie anrufen
next()
auf den iterator (dies geschieht in einer for-Schleife) Ausführung Zentimeter vorwärts zum nächsten yield.return
wirft StopIteration und endet die Serie (das ist das Natürliche Ende einer for-Schleife).Ausbeute ist vielseitig. Daten, die nicht gespeichert werden müssen, alle zusammen, kann verfügbar gemacht werden, ein zu einer Zeit. Es kann unendlich sein.
Wenn Sie brauchen, mehrere Pässe und die Serie ist auch nicht zu lang, einfach anrufen
list()
:Brillante Wahl des Wortes
yield
weil beide Bedeutungen gelten:...bieten die nächsten Daten der Serie.
...verzichten CPU-Ausführung, bis der iterator Fortschritte.
InformationsquelleAutor Bob Stein
Ertrag gibt Ihnen einen generator.
Wie Sie sehen können, im ersten Fall
foo
hält die gesamte Liste im Speicher auf einmal. Es ist nicht eine große Sache für eine Liste mit 5 Elementen, aber was, wenn Sie eine Liste der 5 Millionen? Dies ist nicht nur eine große Speicher-Fresser, es kostet auch eine Menge Zeit zum bauen an der Zeit, dass die Funktion aufgerufen wird.Im zweiten Fall
bar
gibt Ihnen lediglich einen generator an. Ein generator ist ein durchsuchbar-was bedeutet, können Sie es in einfor
loop, etc, aber jeder Wert kann nur aufgerufen werden, einmal. Alle Werte werden auch nicht im Speicher abgelegt, in der gleichen Zeit, die generator-Objekt "merkt" sich, wo es war in der Schleife das Letzte mal, dass Sie es nannten--auf diese Weise, wenn Sie einen wiederholenden um (sagen wir) zählen auf 50 Milliarden, Sie müssen nicht count auf 50 Milliarden alle auf einmal und speichern Sie die 50 Milliarden zahlen zu zählen, die durch.Wieder, das ist ein ziemlich gekünstelt Beispiel, werden Sie wahrscheinlich verwenden würde itertools, wenn Sie wirklich wollen, zu zählen, zu 50 Milliarden Euro. 🙂
Dies ist die einfache Nutzung bei Generatoren. Als Sie sagte, es kann verwendet werden, zu schreiben effiziente Permutationen, mit Ertrag zu push Dinge durch den call-stack, statt über irgendeine Art von stack-variable. Generatoren können auch verwendet werden, für spezialisierte Baum-traversal -, und allerlei andere Dinge.
range
gibt auch einen generator statt einer Liste, so würden Sie auch sehen, eine ähnliche Idee, nur dass__repr__
/__str__
überschrieben werden, um zu zeigen, ein schöneres Ergebnis, in diesem Fallrange(1, 10, 2)
.InformationsquelleAutor RBansal
Es ist die Rückkehr eines Generators. Ich bin nicht besonders vertraut mit Python, aber ich glaube, es ist die gleiche Art der Sache als C#'s iterator-Blöcke wenn Sie vertraut mit diesen.
Die zentrale Idee ist, dass der compiler/interpreter/whatever, macht ein paar Tricks, so dass, wie weit da der Anrufer ist besorgt, Sie können halten Aufruf next() und es wird immer wieder Werte - , als ob der generator-Methode angehalten wurde. Nun man kann natürlich nicht wirklich "pause" eine Methode, damit der compiler baut eine state machine für Sie zu erinnern, wo Sie gerade sind und was die lokalen Variablen etc Aussehen. Dies ist viel einfacher als das schreiben einer iterator selbst.
InformationsquelleAutor Jon Skeet
Es ist eine Art von Antwort, dass ich nicht das Gefühl gegeben wurde noch, unter den vielen tollen Antworten, die beschreiben, wie Generatoren. Hier ist die Programmiersprache Theorie Antwort:
Den
yield
- Anweisung in Python gibt einen generator. Ein generator in Python wird eine Funktion zurückgibt, die Fortsetzungen (und speziell für die Art der koroutine, aber Fortsetzungen vertreten, die mehr die Allgemeinen Mechanismus zu verstehen, was Los ist).Fortsetzungen in Programmiersprachen-Theorie ist eine viel grundsätzlichere Art der Berechnung, aber Sie sind nicht Häufig verwendet, weil Sie extrem hart zu Grunde geht und auch sehr schwierig zu implementieren. Aber die Idee von dem, was eine Fortsetzung ist, ist einfach: es ist der Staat, der eine Berechnung, die noch nicht beendet ist. In diesem Zustand werden die aktuellen Werte der Variablen, die Operationen, die noch durchgeführt werden, und so weiter gespeichert. Dann irgendwann später im Programm die Fortsetzung aufgerufen werden kann, so dass der Programm-Variablen werden zurückgesetzt, der Zustand und die Vorgänge gespeichert wurden, durchgeführt werden.
Fortsetzungen, in diesem mehr Allgemeinen form, kann auf zwei Arten implementiert werden. In der
call/cc
Weg, den Programm-stack ist buchstäblich gerettet und dann, wenn die Fortsetzung aufgerufen wird, wird der stack wiederhergestellt.In continuation passing style (CPS), die Fortsetzungen sind einfach nur die normalen Funktionen (nur in den Sprachen, wo die Funktionen sind erste Klasse), die der Programmierer explizit verwaltet und übergibt um an Unterprogramme. In diesem Stil, Programm Zustand wird repräsentiert durch die Verschlüsse (und die Variablen, die zufällig codiert werden) anstatt der Variablen, die sich irgendwo auf dem Stapel. Funktionen zum verwalten von Ablaufsteuerung akzeptieren Fortführung als Argumente (in einigen Varianten von CPS Funktionen annehmen können mehrere Fortsetzungen) und manipulieren die Ablaufsteuerung, indem Sie einfach durch Aufruf Ihnen und der Rückkehr danach. Ein sehr einfaches Beispiel der Fortsetzung vorbei Stil ist wie folgt:
In diesem (sehr einfaches) Beispiel, der Programmierer spart der Betrieb der schreiben tatsächlich, die Datei in einer Fortsetzung (potenziell ein sehr komplexer Vorgang mit vielen details zu schreiben), und dann passiert, dass eine Fortsetzung (ich.e, wie ein erste-Klasse-Schließung) zu einem anderen Betreiber, die nicht ein bisschen mehr verarbeiten, und nennt es dann, wenn nötig. (Ich benutze dieses design-pattern eine Menge im eigentlichen GUI-Programmierung, entweder, weil es spart mir Zeilen code oder, noch wichtiger, zum verwalten von Ablaufsteuerung, nachdem die GUI-Ereignisse auslösen.)
Den rest von diesem post, ohne Verlust der Allgemeingültigkeit, konzipieren Fortsetzungen wie CPS, denn es ist eine Hölle von viel einfacher zu verstehen und zu Lesen.
Reden wir nun über Generatoren in Python. Generatoren sind eine spezielle Unterform der Fortsetzung. In der Erwägung, dass Fortsetzungen sind in der Lage, im Allgemeinen zum speichern des Zustand des Berechnung (d.h., das Programm call-stack), Generatoren sind nur in der Lage, speichern Sie den Zustand der iteration über eine iterator. Obwohl diese definition ist etwas irreführend für bestimmte Anwendungsfälle von Generatoren. Zum Beispiel:
Dies ist eindeutig eine vernünftige iterierbar, deren Verhalten ist gut definiert-jedes mal, wenn der generator durchläuft es, es gibt 4 (und zwar ewig). Aber es ist nicht wahrscheinlich die prototypische Art der wiederholenden in den Sinn kommt, wenn das denken von Iteratoren (d.h.,
for x in collection: do_something(x)
). Dieses Beispiel veranschaulicht die Leistungsfähigkeit von Generatoren: wenn überhaupt, ist ein iterator, der einen generator sparen kann der Staat seine iteration.Wiederholen: Fortsetzungen sparen können, den Zustand eines Programms stack und Generatoren speichern den Zustand der iteration. Dies bedeutet, dass Fortsetzungen mehr viel mächtiger als Generatoren, aber auch, dass Generatoren sind viel, viel einfacher. Sie sind einfacher für die Sprache, die designer zu implementieren, und Sie sind einfacher für den Programmierer zu verwenden (wenn Sie etwas Zeit haben, um zu brennen, versuchen zu Lesen und zu verstehen diese Seite über Fortsetzungen und call/cc).
Aber Sie könnte leicht zu implementieren (und konzipieren) - Generatoren als einfache, spezifische Fall der continuation passing style:
Wenn
yield
genannt wird, erzählt es die Funktion geben Sie eine Fortsetzung. Wenn die Funktion erneut aufgerufen wird, beginnt es von überall dort, wo es aufgehört hat. Also in pseudo-pseudocode (d.h., nicht pseudocode, aber nicht code) der generator istnext
Methode ist grundsätzlich wie folgt:wo die
yield
Schlüsselwort ist eigentlich syntaktischer Zucker für die real-generator-Funktion, die im Grunde so etwas wie:Daran erinnern, dass das ist nur pseudocode und die tatsächliche Umsetzung von Generatoren in Python ist komplexer. Aber als übung um zu verstehen, was Los ist, versuchen Sie es mit der Fortsetzung vorbei-Stil zu implementieren, generator-Objekten ohne Nutzung der
yield
Stichwort.InformationsquelleAutor aestrivex
Hier ist ein Beispiel im Klartext. Ich werde eine Korrespondenz zwischen high-level-menschlichen Konzepten zu low-level-Python-Konzepte.
Möchte ich den Betrieb auf einer Reihe von zahlen, aber ich will nicht stören, mein selbst mit der Erstellung dieser Sequenz, ich will nur den Fokus auf den Betrieb, die ich tun will. Also, ich Tue das folgende:
Dieser Schritt entspricht
def
ining der generator-Funktion, d.h. die Funktion mit einemyield
.Dieser Schritt entspricht dem Aufruf der generator-Funktion, die gibt ein generator-Objekt. Beachten Sie, dass Sie Sag mir nicht, die zahlen doch noch, greifen Sie einfach Ihr Papier und Bleistift.
Dieser Schritt entspricht dem aufrufen
.next()
auf die generator-Objekt.Dieser Schritt entspricht dem generator-Objekt und beendet Ihre Arbeit, und heben Sie ein
StopIteration
Ausnahme Der generator-Funktion nicht benötigen, heben Sie die Ausnahme. Es wird automatisch angehoben, wenn die Funktion endet, oder die Probleme, die einereturn
.Dies ist, was ein generator ist (eine Funktion, die enthält eine
yield
); es beginnt mit der Ausführung, Pausen, Wann immer es tutyield
, und wenn Sie aufgefordert werden, eine.next()
Wert es geht an der Stelle weiter, es war die Letzte. Es passt perfekt von design mit dem iterator-Protokoll von Python, die beschreibt, wie nacheinander Anfrage Werte.Den bekanntesten Benutzer des iterator-Protokolls ist die
for
Befehl in Python. Also, wenn Sie tun, ein:ist es egal, ob
sequence
ist eine Liste, ein string, ein Wörterbuch oder einen generator, der Objekt wie oben beschrieben; das Ergebnis ist das gleiche: Sie Lesen Artikel aus einer Abfolge eins nach dem anderen.Beachten Sie, dass
def
ining eine Funktion, die enthält eineyield
Schlüsselwort ist nicht der einzige Weg, um einen generator erzeugen; es ist nur der einfachste Weg, um eine zu erstellen.Für genauere Informationen Lesen über iterator-Typen, die yield-Anweisung und Generatoren in der Python-Dokumentation.
InformationsquelleAutor tzot
Während viele der Antworten zeigen, warum Sie verwenden würden, ein
yield
um einen generator erzeugen, gibt es mehr Anwendungen füryield
. Es ist ganz einfach zu machen, eine koroutine, die es ermöglicht die Weitergabe von Informationen zwischen zwei code-Blöcke. Ich werde nicht wiederholen, jeder der schönen Beispiele, die schon gegeben worden sind, über die Verwendungyield
um einen generator erzeugen.Zu helfen zu verstehen, was ein
yield
im folgenden code können Sie mit Ihrem finger zu verfolgen, das Durchlaufen jeder code hat eineyield
. Jedes mal, wenn Ihre finger trifft dieyield
müssen Sie warten, für einenext
oder einesend
eingegeben werden. Wenn einnext
heißt, Sie trace durch den code, bis Sie auf dieyield
... der code auf der rechten Seite desyield
ausgewertet und an den Aufrufer zurückgegeben... dann warten Sie. Wennnext
erneut aufgerufen wird, führen Sie eine weitere Schleife durch den code. Sie werden jedoch beachten, dass in eine koroutine,yield
können auch verwendet werden, mit einemsend
... die schicken einen Wert, der vom Aufrufer in nachgeben Funktion. Wenn einsend
gegeben ist, dannyield
erhält der Wert gesendet, und spuckt es aus der linken Seite... dann auf der Spur durch den code fortschreitet, bis Sie auf dieyield
wieder (gibt den Wert am Ende, als wennnext
genannt wurde).Beispiel:
InformationsquelleAutor Mike McKerns
Es ist ein weiterer
yield
Verwendung und Bedeutung (seit Python 3.3):Vom PEP 380 -- Syntax für die übertragung an einen Subgenerator:
Außerdem diese einführen wird (seit Python 3.5):
zu vermeiden, Coroutinen eine Verwechslung mit einem normalen generator (heute
yield
wird in beide).InformationsquelleAutor Sławomir Lenart
Alles tolle Antworten, aber ein bisschen schwer für Anfänger.
Ich nehme an, Sie haben gelernt, die
return
- Anweisung.Als eine Analogie
return
undyield
sind Zwillinge.return
bedeutet 'zurück und stop' während der 'yield` bedeutet 'zurück, aber weiter geht'Ausführen:
Sehen, erhalten Sie nur eine einzelne Zahl, sondern als eine Liste von Ihnen.
return
nie erlaubt, Sie herrschen gerne, nur einmal implementiert und beenden.Ersetzen
return
mityield
:Nun, Sie gewinnen, um alle zahlen.
Vergleich zu
return
die läuft einmal und Stoppt,yield
läuft Sie mal geplant.Interpretieren Sie
return
alsreturn one of them
, undyield
alsreturn all of them
. Dies wird alsiterable
.Es ist der Kern über
yield
.Den Unterschied zwischen einer Liste
return
Ausgänge und das Objektyield
Ausgabe:Erhalten Sie immer [0, 1, 2] von einem list-Objekt, sondern nur abgerufen werden konnten, Sie von 'dem Objekt
yield
Ausgabe' einmal. So, es hat einen neuen Namengenerator
Objekt angezeigtOut[11]: <generator object num_list at 0x10327c990>
.Im Abschluss, als eine Metapher zu verstehen:
return
undyield
sind Zwillingelist
undgenerator
sind Zwillingeyield
. Dies ist wichtig, denke ich, und sollte zum Ausdruck gebracht werden.InformationsquelleAutor DummyHead
Hier sind einige Python-Beispiele, wie Sie auch tatsächlich umzusetzen, Generatoren, als ob Python nicht syntaktischer Zucker für Sie:
Als Python-generator:
Über lexikalische Verschlüsse anstelle von Generatoren
Mit dem Objekt-Verschlüsse anstelle von Generatoren (weil ClosuresAndObjectsAreEquivalent)
InformationsquelleAutor Dustin Getz
Ich ging zur post "Lesen Sie Seite 19 von Beazley 's" Python: Essential Reference "für eine kurze Beschreibung der Generatoren", aber so viele andere gepostet haben gute Beschreibungen schon.
Beachten Sie auch, dass
yield
können verwendet werden Coroutinen, wie das duale, die in generator-Funktionen. Es ist zwar nicht die gleichen verwenden wie Ihr code-snippet,(yield)
verwendet werden kann als ein Ausdruck in einer Funktion. Wenn ein Anrufer sendet einen Wert an die Methode mit dersend()
Methode, dann wird die coroutine wird ausgeführt, bis die nächste(yield)
- Anweisung angetroffen wird.Generatoren und Coroutinen sind eine Coole Art und Weise so einrichten, Daten-flow-Typ-Anwendungen. Ich dachte, es wäre sinnvoll zu wissen, über die andere Nutzung der
yield
- Anweisung in Funktionen.InformationsquelleAutor johnzachary
Aus Programmier-Sicht, die Iteratoren implementiert werden als thunks.
Zur Implementierung Iteratoren, Generatoren und thread-pools für die gleichzeitige Ausführung etc. als thunks (auch als anonyme Funktionen), verwendet man E-Mails an eine closure-Objekt, das ein dispatcher, dispatcher Antworten auf "Nachrichten".
http://en.wikipedia.org/wiki/Message_passing
"nächsten" wird eine Nachricht gesendet, um eine Schließung, erstellt von der "iter" nennen.
Gibt es viele Möglichkeiten, zu implementieren Sie diese Berechnung. Ich benutzte mutation, aber es ist einfach zu tun, ohne mutation, durch Rücksendung der aktuelle Wert und der nächste Ertrag.
Hier ist eine demonstration, die wird die Struktur der R6RS, aber die Semantik ist absolut identisch mit Python. Es ist das gleiche Modell der Berechnung, und nur eine änderung in der syntax ist erforderlich, um zu umschreiben, dass es in Python.
InformationsquelleAutor alinsoar
Hier ist ein einfaches Beispiel:
Ausgabe:
Ich bin kein Python-Entwickler, aber es sieht für mich
yield
hält die position der Programmablauf und die nächste Schleife starten von "yield" - position. Es scheint, wie es ist, wartet in dieser position, und kurz vor, gibt einen Wert zurück, draußen und in der nächsten Zeit weiter arbeiten.Scheint es eine interessante und schöne Möglichkeit 😀
Sind Sie richtig. Aber was ist der Effekt auf das flow-was ist zu sehen, das Verhalten der "Ertrag" ? Ändern kann ich den Algorithmus im Namen der Mathematik. Wird es helfen, um verschiedene Bewertung der "Ertrag" ?
InformationsquelleAutor Engin OZTURK
Hier ist ein mentales Bild von dem, was
yield
tut.Ich mag zu denken, der einen thread als Stapel (auch wenn es nicht umgesetzt).
Wenn eine normale Funktion aufgerufen wird, legt es seine lokalen Variablen auf den stack, führt eine Berechnung aus, dann löscht den stack und zurück. Die Werte der lokalen Variablen werden nie wieder gesehen.
Mit einem
yield
- Funktion, wenn Ihr code beginnt zu laufen (also nach der Funktion aufgerufen, die ein generator-Objekt, dessennext()
Methode wird dann aufgerufen), ist es ähnlich stellt seine lokalen Variablen in den stack und berechnet für eine Weile. Aber dann, wenn es trifft dieyield
Anweisung, vor der Lichtung seinen Teil des Stacks und Rückkehr, es dauert eine Momentaufnahme der lokalen Variablen und speichert Sie in der generator-Objekt. Er schreibt auch unten den Ort, wo es derzeit bis zu dem code (D. H. der speziellenyield
- Anweisung).Es ist also eine Art gefrorene Funktion, die den generator hängen auf.
Wenn
next()
aufgerufen wird anschließend ruft die Funktion die Sachen auf den stack und re-animiert. Die Funktion wird fortgesetzt, um zu berechnen, von wo es aufgehört hat, blind gegenüber der Tatsache, dass es war nur verbrachte eine Ewigkeit in der kalten Lagerung.Vergleichen Sie die folgenden Beispiele:
Beim aufrufen der zweiten Funktion, es verhält sich ganz anders als die erste. Die
yield
- Anweisung könnte nicht erreichbar sein, aber wenn es vorhanden ist, überall, es ändert sich die Art von dem, was wir zu tun haben.Aufrufen
yielderFunction()
nicht seinen code, macht aber einen generator, der aus dem code. (Vielleicht ist es eine gute Idee, die Namen solcher Dinge, die mit deryielder
Präfix zur besseren Lesbarkeit.)Den
gi_code
undgi_frame
Felder sind, wo gefrorenem Zustand gelagert wird. Erkunden Sie mitdir(..)
können wir bestätigen, dass unsere mentalen Modell oben, ist glaubwürdig.InformationsquelleAutor Evgeni Sergeev
Wie jede Antwort suggeriert,
yield
für das erstellen einer Sequenz-generator. Es ist für die Erstellung eine Sequenz dynamisch. Zum Beispiel beim Lesen einer Datei Zeile für Zeile in einem Netzwerk verwenden, können Sie dieyield
- Funktion wie folgt:Können Sie es verwenden, in Ihrem code wie folgt:
Kontrolle der Durchführung-Transfer-gotcha
Die Steuerung der Ausführung geht von getNextLines (), um die
for
Schleife, wenn die Rendite ausgeführt wird. Jedes mal, wenn getNextLines() aufgerufen, wird die Ausführung beginnt an der Stelle, wo er unterbrochen wurde Letzte mal.Also kurz gesagt, eine Funktion mit dem folgenden code
drucken
InformationsquelleAutor Mangu Singh Rajpurohit
Ausbeute ist ein Objekt
Einen
return
in eine Funktion einen einzelnen Wert zurückgeben.Wenn Sie möchten, eine Funktion zur Rückgabe einer riesigen Menge von Werten, verwenden Sie
yield
.Wichtiger
yield
ist ein Barriere.Ist, es wird führen Sie den code in Ihrer Funktion von den Anfängen bis es trifft
yield
. Dann, es werde der erste Wert der Schleife.Dann, jeder weitere Anruf wird ausgeführt, die Schleife, die Sie geschrieben haben in die Funktion ein weiteres mal, wieder am nächsten Wert, bis es gibt keinen Wert zurück.
InformationsquelleAutor Kaleem Ullah
(Meine Antwort unten nur spricht aus der Perspektive der Verwendung von Python-generator, nicht die zugrunde liegende Implementierung des generator-Mechanismus, die mit ein paar tricks stack-und heap-manipulation.)
Wenn
yield
wird verwendet, anstelle vonreturn
in eine python-Funktion, diese Funktion aktiviert ist, zu etwas besonderem berufengenerator function
. Diese Funktion gibt ein Objekt zurück dergenerator
geben. Dieyield
keyword ist ein flag teilt der python compiler zu behandeln solche Funktion speziell. Die normalen Funktionen werden beendet, sobald etwas Wert zurückgegeben wird. Aber mit der Hilfe des Compilers, der generator-Funktion gedacht werden kann, als fortsetzbar. Das ist der Ausführungskontext wird wiederhergestellt werden, und die Ausführung wird fortgesetzt aus dem letzten run. Bis Sie explizit aufrufen zurück, die heben einenStopIteration
Ausnahme (das ist auch Teil des iterator-Protokoll), oder erreichen Sie das Ende der Funktion. Ich fand eine Menge von Referenzen übergenerator
aber das ein aus derfunctional programming perspective
ist den meisten verdauliches.(Das will ich jetzt sprechen über die Gründe, die hinter
generator
, und dieiterator
basiert auf meinem eigenen Verständnis. Ich hoffe, dies kann Ihnen helfen, fassen Sie die wesentliche motivation der iterator-und generator. Solches Konzept zeigt auf, in anderen Sprachen wie C#.)So wie ich das verstehe, wollen wir-Prozess eine Reihe von Daten, die wir in der Regel zuerst die Daten gespeichert, die irgendwo und dann eins nach dem anderen. Aber das naiv Ansatz ist problematisch. Wenn die Datenmenge riesig ist, es ist teuer, speichern Sie Sie als ganzes im Voraus. Also statt der Speicherung der
data
sich direkt, warum nicht speichern Sie irgendeine Art vonmetadata
indirekt, d.h.the logic how the data is computed
.Gibt es 2 Ansätze zu wickeln, wie man Metadaten.
as a class
. Dies ist die so genannteiterator
wer implementiert das iterator-Protokoll (d.h. die__next__()
, und__iter__()
Methoden). Dies ist auch allgemein-gesehen iterator-Entwurfsmuster.as a function
. Dies istdie so genannte
generator function
. Aber unter der Haube, die zurückgegebengenerator object
nochIS-A
iterator, weil es auch implementiert das iterator-Protokoll.Entweder Weg, einen iterator erstellt wird, d.h. ein Objekt geben kann, dass Sie die Daten, die Sie wollen. Der OO-Ansatz ist vielleicht ein bisschen Komplex. Jedenfalls, die man zu verwenden ist bis zu Ihnen.
InformationsquelleAutor smwikipedia
In der Zusammenfassung, die
yield
- Anweisung wandelt Sie Ihre Funktion in einer Fabrik, die produziert ein spezielles Objekt genanntgenerator
welche den Körper umhüllt, die Ihre ursprüngliche Funktion. Wenn diegenerator
iteriert wird, führt Sie Ihre Funktion bis zum erreichen der nächstenyield
dann unterbricht die Ausführung und wertet die übergebene Wert zuyield
. Es wiederholt diesen Vorgang für jede iteration, bis der Pfad der Ausführung beendet die Funktion. Zum Beispiel,einfach Ausgänge
Kommt der Strom aus der Verwendung der generator mit einer Schleife berechnet eine Sequenz, die der generator führt die Schleife stoppen jedes mal auf 'Ertrag' das nächste Ergebnis der Berechnung, die in dieser Weise berechnet er eine Liste auf der fliege, den nutzen, den Speicher gespeichert, die speziell für große Berechnungen
Sagen, Sie wollten einen eigenen
range
Funktion, erzeugt einen wiederholenden Bereich von zahlen, könnten Sie es ja gerne machen,und es so zu benutzen;
Aber das ist ineffizient, weil
Glücklicherweise Guido und sein team waren großzügig genug, um zu entwickeln, Generatoren, so konnten wir gerade tun;
Nun bei jeder iteration eine Funktion, die generator genannt
next()
führt die Funktion, bis es entweder erreicht ein 'yield' statement, in dem er Stoppt und 'Erträge' der Wert erreicht oder das Ende der Funktion. In diesem Fall auf den ersten Anrufnext()
führt bis zu der Anweisung yield und Ausbeute 'n', auf den nächsten Anruf wird ausgeführt, die Inkrement-Anweisung, springen Sie zurück zu der 'while', bewerten, und wenn das stimmt, wird es anhalten und Ertrag 'n' wieder, es wird auch weiterhin so, bis die while-Bedingung gibt false zurück, und der generator springt an das Ende der Funktion.InformationsquelleAutor redbandit
Viele Menschen nutzen
return
eher alsyield
, aber in einigen Fällenyield
effizienter und einfacher, mit zu arbeiten.Hier ist ein Beispiel, das
yield
ist definitiv am besten für:Beide Funktionen das gleiche tun, aber
yield
verwendet drei Zeilen statt fünf und hat man weniger Variablen zu befürchten.Wie Sie sehen können beide Funktionen das gleiche tun. Der einzige Unterschied ist
return_dates()
gibt eine Liste undyield_dates()
gibt einen generator.Ein Beispiel aus der Praxis wäre so etwas wie das Lesen einer Datei Zeile für Zeile, oder wenn Sie wollen einfach nur, um einen generator.
InformationsquelleAutor Tom Fuller
yield
ist wie ein return-element für eine Funktion. Der Unterschied ist, dass dieyield
element dreht, eine Funktion in einen generator. Ein generator verhält sich wie eine Funktion, bis etwas ist 'ergab'. Der generator anhält, bis es wird weiter genannt, und setzt sich aus genau den gleichen Punkt, wie es begann. Sie können eine Folge von all der 'ergab' - Werte in einem durch den Aufruflist(generator())
.InformationsquelleAutor Theoremiser
Den
yield
Stichwort einfach sammelt Ergebnisse zurückgegeben. Denkenyield
wiereturn +=
InformationsquelleAutor Bahtiyar Özdere
Hier ist eine einfache
yield
basierten Ansatz zur Berechnung der fibonacci-Reihe, erklärt:Wenn Sie geben Sie diese in Ihren REPL und dann versuchen, und nennen Sie es, erhalten Sie eine verwirrende Ergebnis:
Dies ist, weil die Anwesenheit von
yield
signalisiert Python, die Sie erstellen möchten ein generator, das heißt, ein Objekt, das Werte generiert auf Nachfrage.So, wie generieren Sie diese Werte? Diese kann entweder direkt über die integrierte Funktion
next
oder indirekt durch Verfütterung an ein Konstrukt, das verbraucht Werte.Mithilfe der integrierten
next()
Funktion, die Sie direkt aufrufen.next
/__next__
, zwingt den generator zum erzeugen eines Wertes:Indirekt, wenn Sie
fib
zu einemfor
Schleife, einlist
Initialisierer, eintuple
Initialisierer, oder irgendetwas anderes, die erwartet, dass ein Objekt erzeugt/produziert Werte, Sie "verbrauchen" des Generators, bis keine Werte mehr produziert werden kann, indem es (und gibt es):Ebenso mit einem
tuple
Initialisierer:Einen generator unterscheidet sich von einer Funktion in dem Sinne, dass es faul ist. Dies wird erreicht durch die Aufrechterhaltung es ist die lokale Staat, und damit Sie fortsetzen, Wann immer Sie Sie benötigen.
Beim ersten aufrufen
fib
durch aufrufen:Python kompiliert die Funktion, trifft auf die
yield
Schlüsselwort und einfach gibt ein generator-Objekt zurück. Nicht sehr hilfreich, es scheint.Wenn Sie dann fordern, die es erzeugt den ersten Wert, direkt oder indirekt, führt er alle Aussagen, die er findet, bis es auf eine
yield
es ergibt dann wieder den Wert, den Sie geliefertyield
und Pausen. Für ein Beispiel, dass besser zeigt, lassen einigeprint
Anrufe (ersetzen mitprint "text"
wenn auf Python 2):Geben Sie nun in der REPL:
haben Sie ein generator-Objekt wartet nun auf einen Befehl für Sie, um einen Wert generieren. Verwenden
next
und sehen, was erhalten ist, gedruckt:Den nicht börsennotierten Ergebnisse sind, was gedruckt wird. Das zitierte Ergebnis ist das, was zurückgegeben wird
yield
. Rufen Sienext
jetzt wieder:Der generator merkt sich am angehalten wurde
yield value
auf und kehrt von dort. Die nächste Nachricht wird ausgedruckt, und die Suche nach deryield
Anweisung zum anhalten auf, führte es dann wieder (aufgrund derwhile
loop).InformationsquelleAutor Jim Fasarakis Hilliard
Einem einfachen Beispiel von, was es ganz einfach erklärt:
yield
Ausgabe:
InformationsquelleAutor Gavriel Cohen