88 votes

Pourquoi next déclenche-t-il un "StopIteration", alors que for effectue un retour normal ?

Dans ce morceau de code, pourquoi l'utilisation de for n'ont pas pour effet de StopIteration ou est le for boucle piégeant toutes les exceptions et sortant ensuite silencieusement ? Dans ce cas, pourquoi avons-nous l'élément superflu return ? ? Ou est-ce que 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 est déclenché par : return None . Quand est-ce que GeneratorExit 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 ce cas, pourquoi ne vois-je pas de traceback ?

116voto

Martijn Pieters Points 271458

En for La boucle écoute StopIteration explicitement.

L'objectif de la for consiste à 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'attrape pas les autres exceptions soulevées par l'objet sur lequel on itère, seulement celle-là.

C'est parce que StopIteration est le signal normal et attendu pour dire à la personne qui itère qu'il n'y a plus rien à produire.

Une fonction de générateur est un type spécial d'itérateur ; elle soulève en effet StopIteration lorsque la fonction est terminée (c'est-à-dire lorsqu'elle revient, donc oui, return None soulève StopIteration ). Il s'agit d'une exigence des itérateurs ; ils doit soulever StopIteration lorsqu'elles sont terminées ; en fait, une fois par StopIteration a été soulevé, en essayant d'obtenir un autre élément de leur part (par le biais de next() ou en appelant le .next() (py 2) ou .__next__() (méthode py 3) sur l'itérateur) doit toujours soulever StopIteration encore.

GeneratorExit est une exception pour communiquer dans le autre direction. Vous êtes explicitement fermeture du site un générateur avec un yield et la façon dont Python communique cette fermeture au générateur est en levant l'option GeneratorExit à l'intérieur de cette fonction. Vous attrapez explicitement cette exception dans la fonction countdown son but est de permettre au générateur de nettoyer les ressources si nécessaire lors de la fermeture.

A GeneratorExit n'est pas propagé à l'appelant ; voir l'option generator.close() documentation .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X