Ich habe einen Generator generator
und auch eine bequeme Methode dazu - generate_all
.
def generator(some_list):
for i in some_list:
yield do_something(i)
def generate_all():
some_list = get_the_list()
return generator(some_list) # <-- Is this supposed to be return or yield?
Sollte generate_all
return
oder yield
? Ich möchte, dass die Benutzer beider Methoden es gleich verwenden, dh
for x in generate_all()
sollte gleich sein
some_list = get_the_list()
for x in generate(some_list)
Antworten:
Generatoren werden faul ausgewertet
return
oderyield
verhalten sich anders, wenn Sie Ihren Code debuggen oder wenn eine Ausnahme ausgelöst wird.Mit
return
Ausnahme der Fälle, in denen Siegenerator
nichts wissen, liegt dies darangenerate_all
, dassgenerator
Sie diegenerate_all
Funktion bereits verlassen haben, wenn sie wirklich ausgeführt wird . Mityield
drin wird esgenerate_all
im Traceback sein.Und wenn es verwendet
yield from
:Dies geht jedoch zu Lasten der Leistung. Die zusätzliche Generatorschicht hat einen gewissen Overhead. Also
return
wird in der Regel etwas schneller alsyield from ...
(oderfor item in ...: yield item
). In den meisten Fällen spielt dies keine große Rolle, da alles, was Sie im Generator tun, normalerweise die Laufzeit dominiert, sodass die zusätzliche Ebene nicht wahrgenommen wird.Hat
yield
jedoch einige zusätzliche Vorteile: Sie sind nicht auf eine einzige iterable beschränkt, sondern können auch problemlos zusätzliche Elemente liefern:In Ihrem Fall sind die Operationen recht einfach und ich weiß nicht, ob es überhaupt notwendig ist, mehrere Funktionen dafür zu erstellen. Man könnte
map
stattdessen einfach den eingebauten oder einen Generatorausdruck verwenden:Beide sollten identisch sein (mit Ausnahme einiger Unterschiede, wenn Ausnahmen auftreten). Und wenn sie einen aussagekräftigeren Namen benötigen, können Sie sie dennoch in eine Funktion einschließen.
Es gibt mehrere Helfer, die sehr häufige Operationen für integrierte Iterables umschließen, und weitere finden Sie im integrierten
itertools
Modul. In solch einfachen Fällen würde ich einfach auf diese zurückgreifen und nur für nicht triviale Fälle Ihre eigenen Generatoren schreiben.Aber ich gehe davon aus, dass Ihr echter Code komplizierter ist, so dass er möglicherweise nicht anwendbar ist, aber ich dachte, es wäre keine vollständige Antwort, ohne Alternativen zu erwähnen.
quelle
Sie suchen wahrscheinlich nach Generator Delegation (PEP380)
Es ist ziemlich prägnant und hat auch eine Reihe anderer Vorteile, wie die Möglichkeit, beliebige / unterschiedliche Iterables zu verketten!
quelle
list
? Es ist ein schlechtes Beispiel, kein echter Code, der in die Frage eingefügt wurde. Ich sollte ihn wahrscheinlich bearbeiten.yield from map(do_something, iterable)
oder sogaryield from (do_something(x) for x in iterable)
yield from
ist also sinnlos, es sei denn, Ihr Wrapper macht etwas anderes generatorisch.return generator(list)
macht was du willst. Aber beachte daswäre gleichwertig, aber mit der Möglichkeit, nach
generator
Erschöpfung mehr Werte zu erzielen . Zum Beispiel:quelle
yield from
undreturn
wann der Verbraucher des Generatorsthrows
eine Ausnahme darin macht - und mit anderen Operationen, die von der Stapelverfolgung beeinflusst werden.Die folgenden zwei Aussagen scheinen in diesem speziellen Fall funktional äquivalent zu sein:
und
Letzteres ist ungefähr das gleiche wie
Die
return
Anweisung gibt den gesuchten Generator zurück. Eineyield from
or-yield
Anweisung verwandelt Ihre gesamte Funktion in etwas, das einen Generator zurückgibt, der den gesuchten Generator durchläuft.Aus Anwendersicht gibt es keinen Unterschied. Intern ist das jedoch
return
wohl effizienter, da es nichtgenerator(list)
in einen überflüssigen Durchgangsgenerator eingewickelt wird. Wenn Sie zu tun planen jede Verarbeitung auf die Elemente des umwickelten Generator, in irgendeiner Form verwendenyield
natürlich.quelle
Du würdest
return
es tun .yield
ing * würde dazu führengenerate_all()
, dass ein Generator selbst ausgewertet wird, und das Aufrufennext
dieses äußeren Generators würde den inneren Generator zurückgeben, der von der ersten Funktion zurückgegeben wird, was nicht das ist, was Sie wollen.*
Nicht mit inbegriffenyield from
quelle