Iterateurs Generateurs
Iterateurs Generateurs
Iterateurs Generateurs
Itérateurs et générateurs
Il est des concepts en Python que l'on utilise sans réellement le savoir. Et pourtant, pour une
bonne maîtrise de notre langage préféré, et pour optimiser notre code, il est indispensable
de savoir comment ces concepts « camouflés » fonctionnent.
Commentez
Concepts Python avancés par GALODE Alexandre
I - Introduction..............................................................................................................................................................3
II - Les itérateurs......................................................................................................................................................... 3
II-A - Présentation.................................................................................................................................................. 3
II-B - La fonction iter() et la méthode next().......................................................................................................... 3
II-C - Créons notre propre itérateur....................................................................................................................... 4
III - Les générateurs.................................................................................................................................................... 5
III-A - Présentation................................................................................................................................................. 5
III-B - Le mot clé « yield »......................................................................................................................................5
IV - Le module itertools............................................................................................................................................... 6
IV-A - Présentation................................................................................................................................................. 7
IV-B - Possibilités offertes...................................................................................................................................... 7
IV-B-1 - Itérateurs infinis...................................................................................................................................7
IV-B-2 - Itérateurs finis......................................................................................................................................7
IV-B-3 - Générateurs combinatoires................................................................................................................. 9
IV-C - Le cas product()........................................................................................................................................ 10
V - Conclusion........................................................................................................................................................... 10
VI - Remerciements................................................................................................................................................... 10
-2-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
I - Introduction
Les itérateurs et les générateurs sont les concepts qui se cachent derrière la possibilité de parcourir une liste dans
une boucle for, les caractères d'une chaîne de caractères, etc.
Si l'on peut se contenter de se servir des fonctionnalités de base, il arrive toujours un moment dans la vie du
développeur où il devra passer au stade supérieur et se plonger dans le fonctionnement de ces fonctionnalités.
Je vous propose ici de passer ce stade et d'approfondir la compréhension du fonctionnement des itérateurs et
générateurs.
II - Les itérateurs
II-A - Présentation
Un itérateur est un objet permettant de parcourir tout autre objet dit « itérable ». Les exemples les plus connus d'objets
itérables sont les chaines de caractères, les listes, les fichiers… Bref tout objet que l'on peut parcourir via un index
(appelés séquences : cf. documentation officielle).
Les itérateurs sont très présents dans Python, et toute personne ayant codé un minimum en Python les a déjà
rencontrés.
Le plus grand avantage des itérateurs est leur faible consommation ressource.
Voici un exemple typique de code s'appuyant sur un itérateur. Dans cet exemple, la boucle FOR récupère l'itérateur
de la liste et l'utilise afin de parcourir la liste.
Python possède une fonction faisant partie des Built-In (fonctions de base) nommée « iter() ». Cette fonction permet
de créer un itérateur sur un objet itérable.
Certains objets tels les listes possèdent déjà leur propre itérateur accessible via __iter__().
On obtient alors un itérateur plus spécifique. Le code vu à l'instant peut ainsi s'écrire :
Vous voyez ici que vous avez bien récupéré un objet de type « iterator ». L'ensemble des objets de type « iterator »
possède une fonction « next() », qui permet de se déplacer dans l'objet itérable.
-3-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
Si vous exécutez ce code, vous vous rendrez compte que le résultat est identique au code initial. Que se passe-t-il
donc dans ce code ? Et à quoi correspond la méthode next() ?
Tout d'abord, nous créons un itérateur sur notre chaîne de caractères. Dans la boucle FOR, le seul lien que nous
prenons en compte est la longueur de cette chaîne de caractères.
Au niveau du print, nous utilisons une fonctionnalité des itérateurs : la méthode « next() ». Cette méthode permet
de déplacer l'index de l'itérateur sur l'objet.
À la création de l'itérateur, cet index peut être considéré comme valant « -1 ». L'appel à la méthode « next() » déplace
le curseur d'une unité, puis renvoie la valeur lue à cet index.
Maintenant que nous avons vu les bases des itérateurs, je vous propose de créer notre propre itérateur afin de
comprendre, entre autres, comment ce dernier sait quand s'arrêter.
Répondons déjà à cette dernière interrogation. Lorsque nous avons atteint le dernier élément, un nouvel appel à
« next() » provoquera simplement une exception de type « StopIteration ». Il suffit alors d'intercepter cette exception
pour arrêter l'itération.
1. class MonIterateur(object):
2. def __init__(self, obj):
3. self.obj = obj
4. self.length = len(obj)
5. self.count = 0
6.
7. def __iter__(self):
8. return self
9.
10. def next(self):
11. if self.count > self.length:
12. raise StopIteration
13.
14. else:
15. result = self.obj[self.count]
16.
17. self.count += 2
18. return result
19.
20. if __name__ == "__main__":
21. chaine = "hello_world"
22. ma_classe_iterateur = MonIterateur(chaine)
23. iterateur = ma_classe_iterateur.__iter__()
24. try:
25. for idx in range(len(chaine)):
26. print(iterateur.next())
27. except StopIteration:
28. print("fin d'iteration")
Cet exemple montre comment arrêter une itération. Outre cela, nous pouvons également voir qu'au sein de la fonction
« next » de notre itérateur maison, nous avons choisi d'utiliser un pas de deux caractères.
De même, nous aurions pu effectuer un traitement sur la donnée lue avant de la renvoyer.
-4-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
Enfin, notez que l'on peut simplifier le code du « if __name__... » avec les lignes suivantes.
1. if __name__ == "__main__":
2. chaine = "hello_world"
3. ma_classe_iterateur = MonIterateur(chaine)
4. try:
5. for lettre in ma_classe_iterateur:
6. print(lettre)
7. except StopIteration:
8. print("fin d'iteration")
III-A - Présentation
Les générateurs sont des objets Python permettant de créer et de manipuler plus aisément les itérateurs, en plaçant
une couche d'abstraction supplémentaire au niveau code.
Il existe deux façons de créer des générateurs. Ils consomment peu de ressources mémoire. Cette faible
consommation est due au fait que lorsqu'une valeur est demandée au générateur, il va la « générer », puis simplement
la retourner, sans rien conserver en mémoire.
Ils ont été introduits par la PEP 255 et se basent sur l'utilisation du mot clé « yield ».
Le mot clé « yield » est à la base des générateurs. C'est grâce à lui qu'un générateur peut fonctionner.
Il peut être assimilé à un « return », à deux principales différences près. Alors qu'un return vous renverra un ensemble
de valeurs (sous forme de liste, chaine de caractères…) et mettra fin à l'exécution de la procédure/fonction/..., un
yield vous retournera une valeur, puis se mettra en pause, en attendant l'appel suivant.
1. def mon_generateur():
2. yield 'h'
3. yield 'e'
4. yield 'l'
5. yield 'l'
6. yield 'o'
7. yield ' '
8. yield 'w'
9. yield 'o'
10. yield 'r'
11. yield 'l'
12. yield 'd'
13.
14. if __name__ == ('__main__'):
15. generateur = mon_generateur()
16. print generateur
17. for value in generateur:
18. print(value)
Que constatons-nous ? Tout d'abord generateur est bien un objet de type « generator ». Ensuite, au niveau du for,
nous appelons une première fois notre objet generateur.
Rappelons que l'objet generateur fonctionne selon notre générateur défini dans « mon_generateur ».
-5-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
Au niveau de la boucle for, au premier appel, il exécute la première ligne, qu'il faut ici interpréter comme « retourne
la valeur h », puis le générateur se met en pause. Au second appel, il se réveille de sa position et exécute la ligne
suivante, l'équivalent d'un « retourne la valeur e » puis se met en pause. Et ainsi de suite jusqu'à la fin.
1. def mon_generateur(data):
2. for value in data:
3. yield value
4.
5. if __name__ == ('__main__'):
6. generateur = mon_generateur("hello world")
7. print generateur
8. for value in generateur:
9. print(value)
1. def mon_generateur(data):
2. iterateur = iter(data)
3. for idx in range(len(data)):
4. yield iterateur.next()
5.
6. if __name__ == ('__main__'):
7. generateur = mon_generateur("hello world")
8. print generateur
9. for value in generateur:
10. print(value)
Ce code réalise la même chose que précédemment, mais en mettant explicitement en vue l'itérateur.
Avouez tout de même que les générateurs permettent de simplifier l'écriture du code. Qui plus est, étant un niveau plus
bas dans le fonctionnement du code, nous pourrions réaliser des traitements plus en amont (exemple ici : remplacer
les lettres L par le chiffre 1).
1. def mon_generateur(data):
2. for value in data:
3. yield value
4.
5. if __name__ == ('__main__'):
6. generateur = mon_generateur("hello world")
7. print generateur
8. for value in generateur:
9. if value == 'w':
10. generateur.close()
11. else:
12. print(value)
IV - Le module itertools
Maintenant que nous avons vu itérateurs et générateurs, il faut mettre en évidence ce qui constitue à la fois leur
principal avantage et principal défaut : rien n'est gardé en mémoire, tout est volatil.
De fait, il peut s'avérer difficile dans certains cas de prendre conscience de l'ampleur du travail à effectuer et de savoir
comment l'optimiser proprement.
-6-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
IV-A - Présentation
Comme son nom l'indique, le module itertools fournit un ensemble d'outils pour itérateurs. Plus précisément, il met
à disposition un ensemble de fonctionnalités permettant de simplifier tout un ensemble d'opérations, comme une
double boucle for imbriquée.
-7-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
-8-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
Vous constaterez que permutations() vous renvoie l'ensemble des permutations possibles,
en tenant compte de l'ordre (ex. : ('A','B') et ('B','A') seront tous deux renvoyés), alors que
combinations() ne tiendra pas compte de l'ordre (ex. : ('A','B') et ('B','A') seront considérés
comme équivalents et seul l'un d'eux sera renvoyé).
-9-
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/
Concepts Python avancés par GALODE Alexandre
« product() » fait partie des fonctions que vous verrez souvent. En effet, il permet de remplacer avantageusement
une double boucle for imbriquée.
Pour mieux comprendre l'intérêt d'utiliser le module itertools, je vous propose d'exécuter le code suivant.
Comme on peut le constater, le code avec itertools.product() est plus rapide d'environ 20 %. À l'échelle de notre
exemple, cela est négligeable. Mais dans des traitements de masse, cela peut changer énormément les choses.
Sans parler du gain en lisibilité et en simplicité.
V - Conclusion
Comme nous venons de le voir ensemble, le fonctionnement des itérateurs et des générateurs est élémentaire, et
n'a rien de complexe.
En revanche, si un débutant peut très bien se passer de les connaître, ce n'est pas le cas des développeurs confirmés.
En effet, ce concept Python pourra leur permettre d'optimiser profondément leur code et s'avérer indispensable dans
certains cas.
Côté module, itertools est un grand classique dont il faut au minimum connaître le nom et les possibilités. D'autant
plus que dans certains algorithmes, il se révélera vite incontournable. Sans compter que, comme vu il y a peu, le
code n'en devient que plus lisible.
J'espère que ce petit tutoriel vous permettra désormais d'améliorer votre code et d'appréhender plus facilement
certaines erreurs que vous pourriez commettre.
VI - Remerciements
• Lolo78
• ClaudeLELOUP
- 10 -
Le contenu de cet article est rédigé par Alexandre GALODE et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage
dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.
http://deusyss.developpez.com/tutoriels/Programmation/introduction_iterateurs_generateurs/