Dans votre premier exemple, vous avez créé un nouveau à chaque fois :
x().next()
Cela permet de démarrer le générateur depuis le sommet donc la première déclaration. Lorsque a == 3
l'exception est levée, sinon le générateur produit un résultat et fait une pause .
Lorsque vous attribuerez votre générateur par la suite, le système global a
a commencé à 5
Le code est alors le suivant suite à partir de l'endroit où il s'est arrêté jusqu'à ce qu'il se termine ou qu'il rencontre une autre personne. yield
alors terminé . Lorsqu'une fonction génératrice se termine, elle lève StopIteration
.
Nous allons décomposer cela en plusieurs étapes :
-
a = 5
.
-
Vous créez un nouveau générateur et appelez .next()
sur celui-ci. Le code suivant est exécuté :
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 4
yield a
Le générateur est mis en pause sur la dernière ligne, et 4
est obtenue.
-
Vous créez un nouveau générateur et appelez .next()
sur celui-ci. a
est 4
au début :
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 3
yield a
Le générateur est mis en pause sur la dernière ligne, et 3
est obtenue.
-
Vous créez un nouveau générateur et appelez .next()
sur celui-ci. a
est 3
au début :
global a
if a == 3: # True
raise Exception("Stop")
Une exception est levée.
-
Vous définissez a = 5
encore une fois.
-
Vous créez un nouveau générateur, vous stockez une référence dans le fichier b
et appeler .next()
sur celui-ci. Le code suivant est exécuté :
global a
if a == 3: # False
raise Exception("Stop")
a = a - 1 # a is now 4
yield a
Le générateur est mis en pause sur la dernière ligne, et 4
est obtenue.
-
Vous appelez .next()
à nouveau sur le même générateur existant référencé par b
. Le code CV au point de pause.
La fonction n'a plus de code à ce moment-là et retourne. StopIteration
est levé.
Si vous deviez utiliser un boucle au lieu de cela, vous verriez mieux la différence :
>>> def looping(stop):
... for i in looping(stop):
... yield i
...
>>> looping(3).next()
0
>>> looping(3).next()
0
Notez qu'à chaque fois que je crée un nouveau générateur, la boucle recommence au début. Enregistrez une référence cependant, et vous remarquerez qu'elle continue à la place :
>>> stored = looping(3)
>>> stored.next()
0
>>> stored.next()
1
>>> stored.next()
2
>>> stored.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Pendant la boucle, chaque fois que le yield
est exécutée, le code est en pause ; appel .next()
reprend la fonction là où elle s'est arrêtée la fois précédente.
En StopIteration
L'exception est tout à fait normale ; c'est la façon dont les générateurs communiquent qu'ils ont terminé. A for
recherche cette exception pour mettre fin à la boucle :
>>> for i in looping(3):
... print i
...
0
1
2