Puede usarlo return
una vez en un generador; detiene la iteración sin producir nada y, por lo tanto, proporciona una alternativa explícita a dejar que la función se ejecute fuera de alcance. Por lo tanto, use yield
para convertir la función en un generador, pero preceda con return
para terminar el generador antes de generar nada.
>>> def f():
... return
... yield
...
>>> list(f())
[]
No estoy seguro de que sea mucho mejor que lo que tiene, simplemente reemplaza una if
declaración de no operación con una declaración de no operación yield
. Pero es más idiomático. Tenga en cuenta que el solo uso yield
no funciona.
>>> def f():
... yield
...
>>> list(f())
[None]
¿Por qué no usar iter(())
?
Esta pregunta se refiere específicamente a una función de generador vacía . Por esa razón, lo considero una pregunta sobre la consistencia interna de la sintaxis de Python, en lugar de una pregunta sobre la mejor manera de crear un iterador vacío en general.
Si la pregunta es sobre la mejor manera de crear un iterador vacío, entonces podría estar de acuerdo con Zectbumo sobre usarlo en su iter(())
lugar. Sin embargo, es importante observar que iter(())
no devuelve una función. Devuelve directamente un iterable vacío. Suponga que está trabajando con una API que espera un invocable que devuelve un iterable. Tendrás que hacer algo como esto:
def empty():
return iter(())
(El crédito debe ir a Unutbu por dar la primera versión correcta de esta respuesta).
Ahora, puede encontrar lo anterior más claro, pero puedo imaginar situaciones en las que sería menos claro. Considere este ejemplo de una larga lista de definiciones de funciones de generador (artificiales):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
Al final de esa larga lista, prefiero ver algo con un yield
en él, como esto:
def empty():
return
yield
o, en Python 3.3 y superior (como sugiere DSM ), esto:
def empty():
yield from ()
La presencia de la yield
palabra clave deja claro a simple vista que esta es solo otra función generadora, exactamente como todas las demás. Se necesita un poco más de tiempo para ver que la iter(())
versión está haciendo lo mismo.
Es una diferencia sutil, pero honestamente creo que las yield
funciones basadas en son más legibles y fáciles de mantener.
if False: yield
pero sigue siendo un poco confuso para las personas que no conocen este patrónitertools.empty()
.return
significa algo diferente dentro de los generadores. Es más comobreak
.False
.No necesita un generador. ¡Vamos chicos!
fuente
iter([])
por el simple hecho de que()
es una constante mientras[]
puede instanciar un nuevo objeto de lista en la memoria cada vez que se llama.empty = lambda: iter(())
odef empty(): return iter(())
.tuple_iterator
lugar de agenerator
. Si tiene un caso en el que su generador no necesita devolver nada, no use esta respuesta.Python 3.3 (porque estoy en una
yield from
patada, y porque @senderle robó mi primer pensamiento):Pero tengo que admitir que me está costando encontrar un caso de uso para esto para el cual
iter([])
o(x)range(0)
no funcionaría igualmente bien.fuente
return; yield
oif False: yield None
.iter([])
o(x)range(0)
no funcionaría igualmente bien". -> No estoy seguro de qué(x)range(0)
es, pero un caso de uso puede ser un método destinado a ser anulado con un generador completo en algunas de las clases heredadas. Por motivos de coherencia, querrá que incluso el base, del que otros heredan, devuelva un generador como los que lo anulan.Otra opcion es:
fuente
Generator[str, Any, None]
¿Debe ser una función de generador? Si no, que tal
fuente
La forma "estándar" de hacer un iterador vacío parece ser iter ([]). Sugerí hacer [] el argumento predeterminado para iter (); esto fue rechazado con buenos argumentos, ver http://bugs.python.org/issue25215 - Jurjen
fuente
Como dijo @senderle, use esto:
Escribo esta respuesta principalmente para compartir otra justificación.
Una razón para elegir esta solución por encima de las demás es que es óptima en lo que respecta al intérprete.
Como podemos ver,
empty_return
tiene exactamente el mismo código de bytes que una función vacía normal; el resto realiza una serie de otras operaciones que no cambian el comportamiento de todos modos. La única diferencia entreempty_return
ynoop
es que el primero tiene activada la bandera del generador:Por supuesto, la fuerza de este argumento depende mucho de la implementación particular de Python en uso; un intérprete alternativo suficientemente inteligente puede notar que las otras operaciones no son útiles y optimizarlas. Sin embargo, incluso si tales optimizaciones están presentes, requieren que el intérprete dedique tiempo a realizarlas y a protegerse contra las suposiciones de optimización que se rompen, como que el
iter
identificador en el alcance global se rebote a otra cosa (aunque eso probablemente indicaría un error si realmente sucedió). En el caso deempty_return
que simplemente no hay nada que optimizar, incluso el relativamente ingenuo CPython no perderá el tiempo en operaciones falsas.fuente
fuente
Quiero dar un ejemplo basado en una clase, ya que aún no hemos recibido ninguna sugerencia. Este es un iterador invocable que no genera elementos. Creo que esta es una forma sencilla y descriptiva de resolver el problema.
fuente