what - working with generators in python
Retorno en generador junto con rendimiento en Python 3.3 (2)
El valor de retorno no se ignora, pero los generadores solo arrojan valores, un return
simplemente termina el generador, en este caso temprano. Avanzar el generador nunca alcanza la declaración de yield
en ese caso.
Siempre que un iterador llegue al ''final'' de los valores para ceder, se debe StopIteration
una StopIteration
. Los generadores no son una excepción. A partir de Python 3.3, sin embargo, cualquier expresión de return
convierte en el valor de la excepción:
>>> def gen():
... return 3
... yield 2
...
>>> try:
... next(gen())
... except StopIteration as ex:
... e = ex
...
>>> e
StopIteration(3,)
>>> e.value
3
Use la función next()
para avanzar iteradores, en lugar de llamar .__next__()
directamente:
print(next(x))
En Python 2 hubo un error cuando el retorno fue junto con el rendimiento en la definición de la función. Pero para este código en Python 3.3
def f():
return 3
yield 2
x = f()
print(x.__next__())
no hay error de que el retorno se use en la función con rendimiento. Sin embargo, cuando se llama a la función __next__
se lanza la excepción StopIteration. ¿Por qué no solo se devuelve el valor 3
? ¿Es este regreso ignorado de alguna manera?
Esta es una nueva característica en Python 3.3 (como notas de comentario, ni siquiera funciona en 3.2). Al igual que el return
en un generador ha sido durante mucho tiempo equivalente a raise StopIteration()
, return <something>
en un generador ahora es equivalente a raise StopIteration(<something>)
. Por esa razón, la excepción que está viendo debe imprimirse como StopIteration: 3
, y el valor es accesible a través del value
del atributo en el objeto de excepción. Si el generador se delega para usar el yield from
(también nuevo) yield from
sintaxis, es el resultado. Ver PEP 380 para más detalles.
def f():
return 1
yield 2
def g():
x = yield from f()
print(x)
# g is still a generator so we need to iterate to run it:
for _ in g():
pass
Esto imprime 1
, pero no 2
.