Sie können return
einmal in einem Generator verwenden; Es stoppt die Iteration, ohne etwas zu ergeben, und bietet somit eine explizite Alternative dazu, dass die Funktion keinen Gültigkeitsbereich mehr hat. Verwenden Sie also yield
, um die Funktion in einen Generator umzuwandeln, aber gehen Sie voran, return
um den Generator zu beenden, bevor Sie etwas liefern.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Ich bin mir nicht sicher, ob es so viel besser ist als das, was Sie haben - es ersetzt nur eine No-Op- if
Anweisung durch eine No-Op- yield
Anweisung. Aber es ist idiomatischer. Beachten Sie, dass nur die Verwendung yield
nicht funktioniert.
>>> def f():
... yield
...
>>> list(f())
[None]
Warum nicht einfach benutzen iter(())
?
Diese Frage bezieht sich speziell auf eine leere Generatorfunktion . Aus diesem Grund verstehe ich es eher als eine Frage zur internen Konsistenz der Python-Syntax als als eine Frage nach dem besten Weg, einen leeren Iterator im Allgemeinen zu erstellen.
Wenn es bei der Frage tatsächlich darum geht, wie ein leerer Iterator am besten erstellt werden kann, können Sie Zectbumo zustimmen , iter(())
stattdessen einen zu verwenden. Es ist jedoch wichtig zu beachten, dass iter(())
keine Funktion zurückgegeben wird! Es gibt direkt eine leere iterable zurück. Angenommen, Sie arbeiten mit einer API, die eine aufrufbare Datei erwartet, die eine iterable zurückgibt . Sie müssen so etwas tun:
def empty():
return iter(())
(Gutschrift sollte an Unutbu gehen, um die erste richtige Version dieser Antwort zu geben.)
Vielleicht finden Sie das oben Genannte klarer, aber ich kann mir Situationen vorstellen, in denen es weniger klar wäre. Betrachten Sie dieses Beispiel einer langen Liste von (erfundenen) Generatorfunktionsdefinitionen:
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
Am Ende dieser langen Liste würde ich lieber etwas mit einem yield
darin sehen, wie folgt:
def empty():
return
yield
oder in Python 3.3 und höher (wie von DSM vorgeschlagen ):
def empty():
yield from ()
Das Vorhandensein des yield
Schlüsselworts macht auf den ersten Blick deutlich, dass dies genau wie alle anderen nur eine weitere Generatorfunktion ist. Es dauert etwas länger, bis festgestellt wird, dass die iter(())
Version dasselbe tut.
Es ist ein subtiler Unterschied, aber ich denke ehrlich, dass die yield
basierten Funktionen besser lesbar und wartbar sind.
if False: yield
aber immer noch etwas verwirrend für Leute, die dieses Muster nicht kennenitertools.empty()
.return
bedeutet etwas anderes in Generatoren. Es ist eher sobreak
.False
.Sie benötigen keinen Generator. Komm schon Leute!
quelle
iter([])
die einfache Tatsache, dass()
eine konstante Zeit[]
jedes Mal, wenn es aufgerufen wird, ein neues Listenobjekt im Speicher instanziieren kann.empty = lambda: iter(())
oder schreiben müsstendef empty(): return iter(())
.Python 3.3 (weil ich einen
yield from
Kick habe und weil @senderle meinen ersten Gedanken gestohlen hat):Aber ich muss zugeben, es fällt mir schwer, einen Anwendungsfall dafür zu finden, für den es nicht so gut funktioniert
iter([])
oder(x)range(0)
nicht.quelle
return; yield
oderif False: yield None
.iter([])
oder(x)range(0)
nicht." -> Ich bin mir nicht sicher, was es(x)range(0)
ist, aber ein Anwendungsfall kann eine Methode sein, die mit einem vollständigen Generator in einigen der erbenden Klassen überschrieben werden soll. Aus Konsistenzgründen möchten Sie, dass sogar der Basisgenerator, von dem andere erben, einen Generator zurückgibt, genau wie diejenigen, die ihn überschreiben.Eine weitere Option ist:
quelle
Muss es eine Generatorfunktion sein? Wenn nicht, wie wäre es?
quelle
Die "Standard" -Methode zum Erstellen eines leeren Iterators scheint iter ([]) zu sein. Ich schlug vor, [] zum Standardargument für iter () zu machen. Dies wurde mit guten Argumenten abgelehnt, siehe http://bugs.python.org/issue25215 - Jurjen
quelle
Wie @senderle sagte, benutze dies:
Ich schreibe diese Antwort hauptsächlich, um eine weitere Rechtfertigung dafür zu teilen.
Ein Grund für die Wahl dieser Lösung gegenüber den anderen ist, dass sie für den Dolmetscher optimal ist.
Wie wir sehen können,
empty_return
hat der genau den gleichen Bytecode wie eine reguläre leere Funktion; Der Rest führt eine Reihe anderer Vorgänge aus, die das Verhalten ohnehin nicht ändern. Der einzige Unterschied zwischenempty_return
undnoop
besteht darin, dass bei ersteren das Generatorflag gesetzt ist:Die Stärke dieses Arguments hängt natürlich stark von der jeweiligen Implementierung von Python ab. Ein ausreichend intelligenter alternativer Interpreter kann feststellen, dass die anderen Operationen nichts Nützliches darstellen, und sie optimieren. Selbst wenn solche Optimierungen vorhanden sind, muss der Interpreter Zeit damit verbringen, sie auszuführen und sich vor dem Bruch von Optimierungsannahmen zu schützen, z. B.
iter
wenn die Kennung im globalen Bereich auf etwas anderes zurückgesetzt wird (obwohl dies höchstwahrscheinlich auf einen Fehler hinweisen würde, wenn dies der Fall ist tatsächlich passiert). Im Falle vonempty_return
gibt es einfach nichts zu optimieren, so dass selbst der relativ naive CPython keine Zeit mit falschen Operationen verschwendet.quelle
quelle