Les itérateurs et les générateurs python

Un itérateur c'est quoi?

Un itérateur est une sorte de curseur qui a pour mission de se déplacer dans une séquence d'objets. L'itérateur permet de parcourir chaque object d'une séquence sans se préoccuper de la structure sous-jacente.

Pourquoi utiliser un itérateur plutôt qu'une liste?

L'itérateur apporte un niveau d'abstraction plus élévé, c'est à dire qu'on ajoute une couche de code en plus pour réaliser une action. Si un jour on devait changer des éléments du code -exemple d'une mise à jour d'une lib ou changement de base de données par exemple- on n'a pas besoin de changer tout notre code puisque cette couche d'abstraction en plus permet de ne changer que ce qui est nécessaire au niveau de la classe et non plus du code. Et cerise sur le macdo, l'itérateur est un objet peu coûteux en utilisation de mémoire.

Créer son propre itérateur

Une liste est un itérateur:

>>> liste = [1,2,3,4,5,6,7,8,9,10]
>>> for x in liste:
...     print x
... 
1
2
3
4
5
6
7
8
9
10

Créons notre propre classe iterateur:

#!/usr/bin/python2.7
#-*- coding: utf-8 -*-

class MonIter():
    
    current=0

    def __init__(self,stop):
        self.stop=stop

    def __iter__(self) :
        return self

    def next(self) :
        self.current+= 1
        
        if self.current>self.stop:
            raise StopIteration

        if self.current == 5:
            print "Quoi déjà 5eme tour?"

        return self.current

Nous pouvons maintenant boucler sur cet élément:

>>> for i in MonIter(10):
...     print i
... 
1
2
3
4
Quoi déjà 5eme tour?
5
6
7
8
9
10

Les générateurs

Les générateurs permettent de créer plus facilement des itérateurs.

Créons un générateur de base:

#!/usr/bin/python2.7
#-*- coding: utf-8 -*-

def generateur():
    yield "a"
    yield "b"
    yield "c"

Ensuite créons un itérateur:

>>> i=generateur()
>>> for v in i:
...     print v
... 
a
b
c

Alors c'est quoi ce bordel on n'y comprend rien. Tout d'abord on remaque qu'il existe un nouveau mot clé, spécialement crée pour les générateurs: yield. Ce mot clé est un peu similaire au return des fonctions sauf qu'il ne signifie pas la fin de l'exécution de la fonction mais une mise en pause et à la prochaine itération la fonction recherchera le prochain yield.

Créons le même itérateur que dans le chapitre précédent:

#!/usr/bin/python2.7
#-*- coding: utf-8 -*-

def generateur(n):
    for i in range(n):
        if i == 5:
            print "Quoi déjà 5eme tour?"
        yield i+1

Bouclons maintenant sur notre iterable:

>>> i=generateur(10)
>>> for v in i:
...     print v
... 
1
2
3
4
5
Quoi déjà 5eme tour?
6
7
8
9
10

Voila, on arrive au même résultat mais avec beaucoup moins de lignes de code.