scdmb
En Python 2 hubo un error cuando return
estaba junto con yield
en una definición de 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 que return
se utiliza en función de yield
. Sin embargo, cuando la función __next__
se llama entonces se lanza una excepción StopIteration
. Por qué no solo hay valor devuelto 3
? Es esto return
de alguna manera ignorado?
Esta es una característica nueva en Python 3.3 (como señala un comentario, ni siquiera funciona en 3.2). Muy parecido return
en un generador ha sido durante mucho tiempo equivalente a raise StopIteration()
, return <something>
en un generador es ahora 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 atributo value
en el objeto de excepción. Si el generador está delegado para usar el (también nuevo) yield from
sintaxis, es el resultado. Ver PEP 380 para 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
.
Martijn Pieters
El valor de retorno no se ignora, pero solo los generadores rendir valores, un return
simplemente finaliza el generador, en este caso antes de tiempo. El avance del generador nunca llega al yield
declaración en ese caso.
Cada vez que un iterador alcanza el ‘final’ de los valores a producir, un StopIteration
deber ser criado. Los generadores no son una excepción. Sin embargo, a partir de Python 3.3, cualquier return
expresión se 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
Utilizar el next()
función para avanzar iteradores, en lugar de llamar .__next__()
directamente:
print(next(x))
-
return
con un valor no se ignora, es un error de sintaxis (en 3.2 y versiones anteriores) o no se ignora (en 3.3 y versiones posteriores).– usuario395760
27 mayo 2013 a las 20:20
-
@delnan: el valor no se usa; no se puede utilizar
return
en lugar de unyield
. La función termina, así queStopIteration
se eleva y el valor de retorno es, en el mejor de los casos, descartado. el OP sabe antes de 3.3, una devolución con valor es un error de sintaxis.– Martijn Pieters
♦27 mayo 2013 a las 20:21
-
return
de hecho no es un reemplazo parayield
pero el valor es no en vano. Está disponible como un atributo del objeto de excepción, yyield from
da un cómodo acceso a la misma.– usuario395760
27 mayo 2013 a las 20:23
-
@delnan: Correcto, lo acabo de encontrar: el atributo de valor de la instancia de StopIteration planteada […] se puede configurar explícitamente […] o automáticamente devolviendo un valor del subgenerador;
– Martijn Pieters
♦27 mayo 2013 a las 20:27