Itérateurs et générateurs en Python orienté objet

Les itérateurs permettent de parcourir des valeurs composites itérables (des objets comme des listes par exemple). Les générateurs permettent de simplifier la création et l’utilisation d’itérateurs. Dans cette nouvelle leçon, nous allons détailler le fonctionnement des itérateurs Python et voir comment définir des générateurs.

 

Les itérateurs

“Itérer” signifie en français classique “répéter, faire une seconde fois”. Dans le contexte de la programmation orienté objet, “itérer” sur un objet signifie parcourir l’objet attribut par attribut pour accéder à leur valeur.

Les itérateurs sont implicitement utilisés chaque fois que nous manipulons des collections de données comme les list, tuple ou string (qui sont des objets dits “itérables”).

La méthode habituelle pour parcourir une collection est d’utiliser une boucle for. Lorsque nous utilisons une boucle for pour parcourir un objet itérable, la boucle appelle en fait en interne la fonction iter() sur l’objet itérable.

Au lieu d’utiliser la boucle for comme indiqué ci-dessus, nous pouvons utiliser la fonction itérateur iter(). Un itérateur est un objet qui représente un flux de données. Il retourne un élément à la fois.

La méthode intégrée Python iter() reçoit un itérable et retourne un objet itérateur. L’objet itérateur renvoyé définit la méthode __next__() qui va accéder aux éléments de l’objet itérable un par un.

Chaque fois que __next__() est appelée, l’élément suivant du flux itérateur est renvoyé. Lorsqu’il n’y a plus d’éléments disponibles, __next__() lève une erreur StopIteration.

Notez qu’on peut également appeler la méthode __next__() manuellement en utilisant la fonction next().

Les fonctions iter et next des itérateurs Python

On va pouvoir définir nos propres itérateurs dans nos classes pour itérer de manière particulière sur nos objets itérables (en partant de la fin, en sautant des caractères, etc.).

Pour cela, il suffit de définir une méthode __iter__() qui renvoie un objet disposant d’une méthode __next__(). Si la classe définit elle-même la méthode __next__(), alors __iter__() peut simplement renvoyer self.

Création d'un itérateur Python

Ici, on crée une classe qui définit un itérateur qui va sauter une donnée de la séquence sur laquelle il Isère à chaque nouveau passage.

 

Les générateurs

La création d’itérateurs peut parfois s’avérer complexe ou contraignante. Les générateurs sont des outils qui nous permettent de créer des itérateurs.

La syntaxe d’un générateur est la même que celle d’une fonction classique à la différence que les générateurs utilisent l’instruction yield à la place de return pour retourner des données.

L’instruction yield va mettre le générateur en pause mais le contexte d’exécution de celui-ci va être conservé, ce qui va nous permettre d’itérer. A chaque fois qu’on appelle un générateur avec next(), le générateur va reprendre son travail jusqu’au prochain yield.

Lorsqu’on définit un générateur, les méthodes __iter__() et __next__() sont créées automatiquement. De plus, les variables locales ainsi que le contexte d’exécution sont sauvegardés automatiquement entre les appels ce qui nous évite d’avoir à utiliser des notations du type self.attribut. Enfin, les générateurs lèvent automatiquement une exception StopIteration lorsqu’ils terminent leur exécution.

Ces fonctionnalités font des générateurs des outils privilégiés pour créer des itérateurs de manière plus simple.

Création d'un générateur Python

Laisser un commentaire

© Pierre Giraud - Toute reproduction interdite - Mentions légales