[PYTHON] Capturer GeneratorQuitter et détecter la fin de l'itération du côté du générateur

L'itérateur lui-même peut ne pas tourner vers la fin à cause de break etc., mais il y a de rares cas où vous voulez tourner l'itération à l'intérieur du générateur jusqu'à la fin.

Exemples qui ne fonctionnent pas

A titre d'exemple, le "range_printsum" suivant ajoute le processus d'impression de la somme de la plage à la fonction "range".

gen.py


def range_printsum(*args, **kwargs):
    sum_ = 0

    for i in range(*args, **kwargs):
        sum_ += i
        yield i

    print(sum_)

Dans cette implémentation du générateur, si l'itération est arrêtée au milieu, ce qui est réellement stocké dans «sum_» est le nombre total de «yield», et «sum_» n'est pas sorti en premier lieu.

>>> from gen import range_printsum
>>> for i in range_printsum(11):
...     pass
...
55
>>> for i in range_printsum(11):
...     if i > 5:
...         break
...
>>>

Des exemples qui fonctionnent

Alors capturez Generator Exit. Ceci est envoyé lorsque le générateur est fermé (lorsque le générateur close () est appelé). Cela peut être capturé même si la boucle telle que «for» est interrompue. Après avoir capturé GeneratorExit, modifiez range_printsum pour qu'il ne renvoie pas de valeur et ajoute seulement.

gen.py


def range_printsum(*args, **kwargs):
    sum_ = 0
    stop_yield = False

    for i in range(*args, **kwargs):
        sum_ += i
        if not stop_yield:
            try:
                yield i
            except GeneratorExit:
                stop_yield = True

    print(sum_)

Cette fois, cela fonctionne comme prévu.

>>> from gen import range_printsum
>>> for i in range_printsum(11):
...     pass
...
55
>>> for i in range_printsum(11):
...     if i > 5:
...         break
...
55
>>>

Cela fonctionne même s'il est interrompu comme ça.

>>> try:
...     for i in range_printsum(11):
...         if i > 5:
...             raise IndexError
... except IndexError:
...     pass
...
55
>>>

Pour mettre en garde les spécifications du générateur, un générateur une fois fermé ne doit pas générer de valeur. Si vous «donnez» une valeur après avoir capturé le «GeneratorExit», vous obtiendrez l'erreur «RuntimeError: generator ignored GeneratorExit».

Recommended Posts

Capturer GeneratorQuitter et détecter la fin de l'itération du côté du générateur
L'opérateur and de l'expression d'évaluation de Python semble être évalué à partir de l'expression de gauche
Othello ~ De la troisième ligne de "Implementation Deep Learning" (4) [Fin]
Remarque DJango: depuis le début (Simplification et fractionnement d'URLConf)
Combinaison de récursif et de générateur
Utilisez Firefox avec Selenium depuis python et enregistrez la capture d'écran
Trouvez la distance (en tenant compte de la rondeur de la terre) de la latitude et de la longitude.
Trouvez le waypoint à partir de la latitude et de la longitude (en tenant compte de la rondeur de la terre).
L'histoire de Python et l'histoire de NaN
Existence du point de vue de Python
Trouvez la broche inertielle et le moment d'inertie principal à partir du tenseur inertiel avec NumPy
Résumez le titre de Hottentori dans Hateb et regardez le présent du Web