Python: Generator-Ausdruck gegen Ausbeute
In Python, gibt es einen Unterschied zwischen der Erstellung eines generator-Objekt durch eine generator-Ausdruck Vergleich mit der Ertrag Aussage?
Mit Ertrag:
def Generator(x, y):
for i in xrange(x):
for j in xrange(y):
yield(i, j)
Mit generator-Ausdruck:
def Generator(x, y):
return ((i, j) for i in xrange(x) for j in xrange(y))
Beide Funktionen geben die generator-Objekte, die Tupel, z.B. (0,0), (0,1) etc.
Irgendwelche Vorteile der einen oder der anderen? Gedanken?
Danke an alle! Es gibt eine Menge toller Informationen und weitere Referenzen in diesen Antworten!
InformationsquelleAutor der Frage cschol | 2010-01-03
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es nur geringe Unterschiede in den beiden. Sie können die
dis
Modul zu prüfen, diese Art der Sache für sich selbst.Edit: Meine erste version dekompiliert der generator-Ausdruck erstellt am Modul-Bereich in der interaktiven Eingabeaufforderung. Das ist etwas anders von der OP-version mit einer Funktion. Ich geändert habe Sie diese zu entsprechen, im konkreten Fall in Frage.
Wie Sie unten sehen können, die "Ausbeute" - generator (Erster Fall) hat drei zusätzliche Anweisungen in der setup, aber ab den ersten
FOR_ITER
Sie unterscheiden sich nur in einer Hinsicht: die "Ausbeute" Ansatz verwendet eineLOAD_FAST
an die Stelle einerLOAD_DEREF
innerhalb der Schleife. DieLOAD_DEREF
ist "eher langsamere" alsLOAD_FAST
ist, so macht es die "Ausbeute" - version etwas schneller als der generator-Ausdruck für eine größere Zahl vonx
(äußere Schleife), weil der Wert dery
geladen ist etwas schneller bei jedem Durchlauf. Für kleinere Werte vonx
würde es etwas langsamer sein, weil der zusätzliche Aufwand für das setup-code.Könnte es auch sein, darauf hinzuweisen, dass der generator-Ausdruck in der Regel verwendet werden inline im code, anstatt wickelte Sie mit der Funktion wie. Das wäre zu entfernen ein wenig von der setup-Aufwand und halten den generator-Ausdruck etwas schneller für kleinere loop-Werte, auch wenn
LOAD_FAST
gab die "Ausbeute" - version einen Vorteil, sonst.In keinem Fall würde der performance-Unterschied rechtfertigt die Entscheidung zwischen der einen oder der anderen. Die Lesbarkeit zählt weit mehr, also je nachdem, was fühlt sich am meisten lesbar sind für die situation bei der hand.
InformationsquelleAutor der Antwort Peter Hansen
In diesem Beispiel nicht wirklich. Aber
yield
kann verwendet werden, für komplexere Konstrukte - beispielsweise es akzeptieren können Werte vom Aufrufer als auch und verändern die Strömung als Ergebnis. Lesen PEP 342 für mehr details (es ist eine interessante Technik, die man wissen sollte).Sowieso, der beste Rat ist, verwenden, was auch immer klarer für Ihre Bedürfnisse.
P. S. Hier ist ein einfaches coroutine-Beispiel aus Dave Beazley:
InformationsquelleAutor der Antwort Eli Bendersky
Es ist kein Unterschied für die Art von einfachen Schleifen, dass Sie können passen in eine generator expression. Aber die Ausbeute kann verwendet werden, um Generatoren, die viel mehr tun, komplexe Verarbeitung. Hier ist ein einfaches Beispiel für die Generierung der fibonacci-Folge:
InformationsquelleAutor der Antwort Dave Kirby
Mit
yield
ist schön, wenn der Ausdruck komplizierter ist, als einfach nur verschachtelte Schleifen. Unter anderem können Sie die Rückgabe einem speziellen ersten oder letzten Wert. Bedenken Sie:InformationsquelleAutor der Antwort Tor Valamo
In Gebrauch, beachten Sie die Unterscheidung zwischen einem generator-Objekt vs eine generator-Funktion.
Einem generator-Objekt ist, verwenden Sie einmal-nur, im Gegensatz zu einer generator-Funktion, die wiederverwendet werden können jedes mal, wenn Sie nennen es wieder, denn es gibt eine frische-generator-Objekt.
Generator-Ausdrücke sind in der Praxis meist verwendete "raw", ohne wickelte Sie in eine Funktion, und Sie kehren ein generator-Objekt.
E. g.:
welche Ausgänge:
Vergleichen mit eine etwas andere Verwendung:
welche Ausgänge:
Vergleichen und mit einem generator-Ausdruck:
die auch-Ausgänge:
InformationsquelleAutor der Antwort Craig McQueen
Beim nachdenken über Iteratoren, die
itertools
Modul:Zur Leistung, betrachten
itertools.product(*iterables [wiederholen])
InformationsquelleAutor der Antwort gimel
Ja, es ist ein Unterschied.
Für den generator-Ausdruck
(x for var in expr)
iter(expr)
wird aufgerufen, wenn der Ausdruck erstellt.Bei der Verwendung
def
undyield
um einen generator erzeugen, in:iter(expr)
noch nicht genannt. Es wird nur aufgerufen werden, wenn die Iteration aufg
(und vielleicht nicht genannt werden).Einnahme dieser iterator als Beispiel:
Diesem code:
während:
Da die meisten Iteratoren nicht tun eine Menge Sachen, die in
__iter__
ist es leicht zu übersehen, dieses Verhalten. Ein reales Beispiel wäre Django ' sQuerySet
die abrufen von Daten im__iter__
unddata = (f(x) for x in qs)
könnte viel Zeit in Anspruch nehmen, währenddef g(): for x in qs: yield f(x)
gefolgt vondata=g()
würde sofort zurückkehren.Weitere Infos und die formale definition siehe PEP 289 -- Generator-Ausdrücke.
InformationsquelleAutor der Antwort Udi
Gibt es eine Differenz, die von Bedeutung sein könnten, in einigen Kontexten, die noch nicht darauf hingewiesen worden doch. Mit
yield
verhindert, dass Sie mitreturn
für etwas anderes als implizit Erhöhung StopIteration (und Coroutinen-related stuff).Dies bedeutet, dass dieser code ist schlecht ausgebildet (und füttern es an einen übersetzer geben Ihnen eine
AttributeError
):Auf der anderen Seite, dieser code funktioniert wie ein Charme:
InformationsquelleAutor der Antwort Adrien