python - barplot - pandas plot
FunciĆ³n de generador de Python Empty (9)
¿Debe ser una función del generador? Si no, ¿qué tal
def f():
return iter([])
En python, uno puede definir fácilmente una función de iterador, colocando la palabra clave yield en el cuerpo de la función, como por ejemplo:
def gen():
for i in range(100):
yield i
¿Cómo puedo definir una función del generador que no produce ningún valor (genera 0 valores)? El siguiente código no funciona, ya que Python no puede saber que se supone que es un generador y no una función normal:
def empty():
pass
Podría hacer algo como
def empty():
if False:
yield None
Pero eso sería muy feo. ¿Hay alguna buena manera de realizar una función de iterador vacía?
La forma "estándar" de hacer un iterador vacío parece ser iter ([]). Sugerí que [] el argumento predeterminado para iter (); esto fue rechazado con buenos argumentos, ver http://bugs.python.org/issue25215 - Jurjen
Otra opción es:
(_ for _ in ())
Para aquellos de ustedes que realmente necesitan una función y realmente necesitan un generador
empty = lambda: (_ for _ in ())
Prefiero lo siguiente:
def foo():
raise StopIteration()
yield
El "rendimiento" lo convierte en un generador, mientras que Excepción significa que Ninguno está incluido en el resultado (resultado puramente vacío).
Puede usar return
una vez en un generador; detiene la iteración sin ceder nada, y por lo tanto proporciona una alternativa explícita para dejar que la función se quede sin alcance. Entonces use yield
para convertir la función en un generador, pero preceda con return
para terminar el generador antes de ceder algo.
>>> def f():
... return
... yield
...
>>> list(f())
[]
No estoy seguro de que sea mucho mejor de lo que tiene, simplemente reemplaza una declaración de no operación con una declaración de yield
operativa. Pero es más idiomático. Tenga en cuenta que el solo uso de yield
no funciona.
>>> def f():
... yield
...
>>> list(f())
[None]
¿Por qué no usar iter(())
?
Esta pregunta pregunta específicamente sobre una función de generador vacía. Por esa razón, considero que se trata de una cuestión de coherencia 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 puede estar de acuerdo con Zectbumo sobre el uso de iter(())
. Sin embargo, es importante observar que iter(())
no devuelve una función. Devuelve directamente un iterable vacío. Supongamos 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 para 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 del generador (artificial):
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
Al final de esa larga lista, prefiero ver algo con yield
, como este:
def empty():
return
yield
o, en Python 3.3 y superior (como sugiere DSM ), esto:
def empty():
yield from ()
La presencia de la palabra clave yield
deja en claro, a simple vista, que esta es solo otra función del generador, exactamente como todas las demás. Se necesita un poco más de tiempo para ver que la versión iter(())
está haciendo lo mismo.
Es una diferencia sutil, pero sinceramente creo que las funciones basadas en el yield
son más legibles y mantenibles.
Python 3.3 (porque estoy en un yield from
kick, y porque @senderle robó mi primer pensamiento):
>>> def f():
... yield from ()
...
>>> list(f())
[]
Pero tengo que admitir que me está costando crear un caso de uso para el cual iter([])
o (x)range(0)
no funcionarían igual de bien.
generator = (item for item in [])
iter(())
No necesitas un generador. ¡Vamos chicos!