Comment définir des fonctions de générateur avec état supplémentaire en Python

Vous aimeriez définir une fonction de générateur, mais cela implique un état supplémentaire que vous aimeriez exposer à l’utilisateur d’une manière ou d’une autre.

Si vous voulez qu’un générateur expose un état supplémentaire à l’utilisateur, n’oubliez pas que vous pouvez facilement l’implémenter en tant que classe, en mettant le code de la fonction générateur dans la méthode __iter__(). Par exemple:

from collections import deque

class histoireLigne:
    def __init__(self, lignes, histlen=3):
        self.lignes = lignes
        self.histoire = deque(maxlen=histlen)

    def __iter__(self):
        for ligneno, line in enumerate(self.lignes,1):
            self.histoire.append((ligneno, ligne))
            yield ligne

    def clear(self):
        self.histoire.clear()

Pour utiliser cette classe, vous la traitez comme une fonction de générateur normale. Cependant, puisqu’il crée une instance, vous pouvez accéder aux attributs internes, tels que l’attribut historique ou la méthode clear(). Par exemple:

with open('fichier.txt') as f:
     lignes = histoireLigne(f)
     for ligne in lignes:
         if 'python' in ligne:
             for ligneno, hligne in lignes.histoire:
                 print('{}:{}'.format(ligneno, hligne), end='')

Avec les générateurs, il est facile de tomber dans le piège d’essayer de tout faire avec des fonctions seulement.

Cela peut conduire à un code assez compliqué si la fonction de générateur doit interagir avec d’autres parties de votre programme de façon inhabituelle (exposition des attributs, autorisation du contrôle via des appels de méthode, etc.).

Si c’est le cas, utilisez tout simplement une définition de classe, comme indiqué.

Définir votre générateur dans la méthode __iter__() ne change rien à la façon dont vous écrivez votre algorithme. Le fait qu’il fasse partie d’une classe vous permet de fournir facilement des attributs et des méthodes avec lesquels les utilisateurs peuvent interagir.

Une subtilité potentielle de la méthode montrée est qu’elle pourrait nécessiter une étape supplémentaire d’appel iter() si vous allez conduire l’itération en utilisant une technique autre qu’une boucle for. Par exemple:

>>> f = open('fichier.txt')
>>> lignes = histoireLigne(f)
>>> next(lignes)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'histoireLigne' object is not an iterator

>>> # appeler iter() d'abord, puis commencer à itérer
>>> it = iter(lignes)
>>> next(it)
'hello world\n'
>>> next(it)
'this is amazing!\n'
>>>

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here