Puoi usare returnuna volta in un generatore; interrompe l'iterazione senza produrre nulla e quindi fornisce un'alternativa esplicita per lasciare che la funzione esca dall'ambito. Quindi usa yieldper trasformare la funzione in un generatore, ma precedilo returnper terminare il generatore prima di cedere qualsiasi cosa.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Non sono sicuro che sia molto meglio di quello che hai - sostituisce semplicemente ifun'istruzione no-op con un'istruzione no-op yield. Ma è più idiomatico. Nota che il semplice utilizzo yieldnon funziona.
>>> def f():
... yield
...
>>> list(f())
[None]
Perché non basta usare iter(())?
Questa domanda chiede specificamente una funzione di generatore vuoto . Per questo motivo, ritengo che sia una domanda sulla coerenza interna della sintassi di Python, piuttosto che una domanda sul modo migliore per creare un iteratore vuoto in generale.
Se la domanda riguarda effettivamente il modo migliore per creare un iteratore vuoto, potresti essere d'accordo con Zectbumo sull'utilizzo iter(()). Tuttavia, è importante osservare che iter(())non restituisce una funzione! Restituisce direttamente un iterabile vuoto. Supponi di lavorare con un'API che si aspetta un chiamabile che restituisce un iterabile. Dovrai fare qualcosa del genere:
def empty():
return iter(())
(Il merito dovrebbe andare a Unutbu per aver fornito la prima versione corretta di questa risposta.)
Ora, potresti trovare quanto sopra più chiaro, ma posso immaginare situazioni in cui sarebbe meno chiaro. Considera questo esempio di un lungo elenco di definizioni di funzioni del generatore (inventate):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
Alla fine di quella lunga lista, preferirei vedere qualcosa con yielddentro, come questo:
def empty():
return
yield
oppure, in Python 3.3 e versioni successive (come suggerito da DSM ), questo:
def empty():
yield from ()
La presenza della yieldparola chiave fa capire al più breve sguardo che questa è solo un'altra funzione del generatore, esattamente come tutte le altre. Ci vuole un po 'più di tempo per vedere che la iter(())versione sta facendo la stessa cosa.
È una sottile differenza, ma onestamente penso che le yieldfunzioni basate su siano più leggibili e gestibili.
if False: yieldma ancora un po 'confuso per le persone che non conoscono questo schema