with - what are python generators used for
¿Cuándo usar el retorno(ceder algo)? (1)
Dentro de un generador, las expresiones (rendimiento 42) producirán el valor 42, pero también devuelve un valor que es Ninguno, si usa next(generator)
o un valor dado si usa generator.send(value)
.
Entonces, como usted dice, podría usar un valor intermedio para obtener el mismo comportamiento, no porque se trate de azúcar sintáctica, sino porque las expresiones de rendimiento están devolviendo literalmente el valor que le envía.
Igualmente podrías hacer algo como
def my_generator():
return (yield (yield 42) + 10)
Si llamamos a esto, usando la secuencia de llamadas:
g = my_generator()
print(next(g))
try:
print(''first response:'', g.send(1))
print(''Second response:'', g.send(22))
print(''third response:'', g.send(3))
except StopIteration as e:
print(''stopped at'', e.value)
Primero obtenemos la salida de 42, y el generador está esencialmente en pausa en un estado que podríamos describir como: return (yield <Input will go here> + 10)
. Si luego llamamos g.send(1)
obtenemos la salida 11 . y el generador está ahora en el estado: return <Input will go here>
, luego el envío de g.send(22)
generará una StopIteration(22)
, debido a la forma en que se maneja el retorno en los generadores. Así que nunca llegas al tercer envío debido a la excepción.
Espero que este ejemplo lo haga un poco más evidente de cómo funciona el yield
en los generadores y de por qué el return (yield something)
la sintaxis return (yield something)
no es nada especial o exótico y funciona exactamente de la manera que lo esperaría.
En cuanto a la pregunta literal, ¿cuándo harías esto? Bueno, cuando quiera dar algo, y luego devolver una StopIteration haciendo eco de la entrada del usuario enviado al generador. Porque esto es literalmente lo que dice el código. Espero que tal comportamiento sea raramente deseado.
Durante mucho tiempo no sabía que no se puede poner el return
frente a una declaración de rendimiento. Pero en realidad puedes:
def gen():
return (yield 42)
que es similar a
def gen():
yield 42
return
Y el único uso que se me ocurre es adjuntar valor enviado a StopIteration
: pep-0380
la devolución de expr en un generador hace que StopIteration (expr) se levante al salir del generador.
def gen():
return (yield 42)
g = gen()
print(next(g)) # 42
try:
g.send(''AAAA'')
except StopIteration as e:
print(e.value) # ''AAAA''
Pero esto también se puede hacer usando una variable adicional, que es más explícita:
def gen():
a = yield 42
return a
g = gen()
print(next(g))
try:
g.send(''AAAA'')
except StopIteration as e:
print(e.value) # ''AAAA''
Así que parece que el return (yield xxx)
es simplemente un azúcar sintáctico. ¿Me estoy perdiendo de algo?