Dans ce morceau de code, pourquoi utiliser for
ne donne-t-il pas StopIteration
ou la boucle for
intercepte-t-elle toutes les exceptions puis se ferme-t-elle en silence? Dans ce cas, pourquoi avons-nous le return
?? Ou est le raise StopIteration
causé par: 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)
En supposant que StopIteration
soit déclenché par: return None
. Quand est-ce que GeneratorExit
est généré?
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 je fais manuellement un:
c = countdown(10)
c.close() #generates GeneratorExit??
Dans quel cas, pourquoi ne vois-je pas de trace?
La boucle for
écoute explicitement StopIteration
.
Le but de l'instruction for
est de boucler sur la séquence fournie par un itérateur et l'exception est utilisée pour signaler que l'itérateur est maintenant terminé; for
n'intercepte pas les autres exceptions déclenchées par l'objet qui est itéré, mais celle-là.
C'est parce que StopIteration
est le signal normal, attendu, qui indique à qui que ce soit itératif qu'il n'y a plus rien à produire.
Une fonction de générateur est un type particulier d’itérateur; il soulève en effet StopIteration
lorsque la fonction est terminée (c’est-à-dire lorsqu’elle revient, donc oui, return None
soulève StopIteration
). C'est une exigence des itérateurs. ils doivent lever StopIteration
lorsqu'ils sont terminés; en fait, une fois qu'un StopIteration
a été levé, il essaie d'obtenir un autre élément (via next()
, ou en appelant la .next()
(py 2) ou la fonction .__next__()
(py 3) sur l’itérateur) doit toujours toujours relancer StopIteration
.
GeneratorExit
est une exception pour communiquer dans le sens autre . Vous êtes explicitement en train de fermer un générateur avec une expression yield
et la manière Python communique cette fermeture Pour que le générateur se trouve en levant GeneratorExit
à l'intérieur de cette fonction, vous capturez explicitement cette exception dans countdown
, son objectif est de permettre à un générateur de nettoyer les ressources si nécessaire lors de la fermeture.
Un GeneratorExit
n'est pas propagé à l'appelant; voir la generator.close()
documentation .