python - has - ¿Por qué a continuación se genera una ''StopIteration'', pero ''for'' hace un retorno normal?
python iter method (1)
En este fragmento de código, ¿por qué el uso de ''for'' no produce ''StopIteration'' o el bucle ''for'' atrapa todas las excepciones y luego sale silenciosamente? ¿En qué caso, por qué tenemos el ''retorno'' extraño? ¿O es el raise StopIteration
causado por: return None
?
#!/usr/bin/python3.1
def countdown(n):
print("counting down")
while n >= 9:
yield n
n -= 1
return
for x in countdown(10):
print(x)
c = countdown(10)
next(c)
next(c)
next(c)
Suponiendo que StopIteration
se desencadena por: return None
. ¿Cuándo se genera GeneratorExit?
def countdown(n):
print("Counting down from %d" % n)
try:
while n > 0:
yield n
n = n - 1
except GeneratorExit:
print("Only made it to %d" % n)
Si hago manualmente un:
c = countdown(10)
c.close() #generates GeneratorExit??
¿En qué caso, por qué no veo una traza?
El bucle for StopIteration
explícitamente StopIteration
.
El propósito de la instrucción for
es recorrer la secuencia proporcionada por un iterador y la excepción se utiliza para indicar que el iterador está listo; for
no captura otras excepciones generadas por el objeto sobre el que se itera, solo esa.
Esto se debe a que StopIteration
es la señal normal y esperada que le dice a quien está iterando que no hay nada más que producir.
Una función de generador es un tipo especial de iterador; de hecho, genera StopIteration
cuando se realiza la función (es decir, cuando regresa, por lo que sí, return None
genera StopIteration
). Es un requisito de los iteradores; deben levantar StopIteration
cuando se hacen; de hecho, una vez que se ha levantado un StopIteration
, intentar obtener otro elemento de ellos (mediante next()
, o llamar al .next()
(py 2) o .__next__()
(py 3) en el iterador) siempre debe elevar StopIteration
nuevo.
GeneratorExit
es una excepción para comunicarse en la otra dirección. Está cerrando explícitamente un generador con una expresión de yield
, y la forma en que Python comunica ese cierre al generador es mediante la creación de GeneratorExit
dentro de esa función. Usted captura explícitamente esa excepción dentro de la countdown
, su propósito es permitir que un generador limpie los recursos según sea necesario al cerrar.
Un GeneratorExit
no se propaga a la persona que llama; Consulte la documentación de generator.close()
.