Itérateurs

On connait la boucle for, qui permet de parcourir les différents éléments d’une liste, d’un tuple, d’une chaîne, ou même d’un dictionnaire ou d’un ensemble. Voici quelques exemple récapitulatifs, où on itère la fonction print sur des objets successifs (intervalle, liste, chaîne, tuple, ensemble, dictionnaire) :

Les itérables sont donc les objets qu’on peut parcourir, soit parce qu’ils sont présents physiquement en mémoire, soit parce qu’ils sont capables de produire toutes leurs valeurs à la demande. Pour illustrer cette différence un peu subtile, on va construire un itérateur un peu particulier avec la fonction map :

On voit ici que notre objet map contient un mécanisme permettant de délivrer des valeurs successives (et qu’il est capable de mémoriser à quel stade il en est resté). On peut ainsi accéder manuellement aux valeurs successives de l’objet m, jusqu’à au dernier (un appel supplémentaire de next provoque alors l’erreur StopIteration) :

Revenons maintenant à la définition initiale de l’objet m, et créons une liste obtenue en convertissant cet objet (avec le constructeur list). De cette manière, nous formons une liste m2 contenant simultanément toutes les valeurs qu’était capable de produire l’objet m. Deux remarques s’imposent : d’une part la taille de l’objet m2 est beaucoup plus grande que celle de m, et d’autre part la conversion de m en la liste m2 a visiblement “épuisé” le mécanisme d’itération de m :

Prenons maintenant un exemple analogue au précédent, mais obtenu avec la fonction filter

Autre exemple, avec la fonction zip, qui forme des tuples d’éléments de même position dans différents itérables :

Nous terminons ce tour d’horizon en évocant les “intervalles” (obtenus par la fonction range de Python), et qui ont été souvent utilisés jusqu’ici (notamment dans les boucles for) :

Quand on évalue une boucle for pour parcourir un objet itérable, c’est le mécanisme next qui est mis en oeuvre dans les coulisses, l’exception StopIteration étant traitée par la boucle for elle-même.

Mais il en est ainsi de nombreux mécanismes qui opèrent sur des objets itérables (la fonction in pour tester l’appartenance, la fonction sum pour calculer une somme, etc).

Il y a une différence subtile entre “itérable” et “itérateur”, les itérateurs étant des fonctions permettant de parcourir les itérables (mais ça fait un peu jargon, tout ça) ; si cette distinction est pertinente pour les “range”, elle ne l’est pas pour les “zip”, “map” et autres “filter”, qui sont leur propre itérateur (got it ?)

Tout ça est en fait assez transparent dans la pratique. On retiendra surtout que l’utilisation d’itérateurs est un moyen efficace (l’empreinte mémoire est faible) d’accéder successivement aux différentes composantes d’un objet itérable (chaîne, liste, tuple, dictionnaire, ensemble, etc.) en évitant de créer simultanément toutes ces composantes en mémoire.

Dernière distinction intéressante : on peut créer plusieurs itérateurs sur un intervalle, ce qui permet de gérer simultanément plusieurs parcours de celui-ci.

Retour à l’accueil du cours Python/Numpy

Sommaire du chapitre 6

  1. Dictionnaires
  2. Ensembles
  3. Itérateurs
  4. Fonctions utiles sur les itérateurs
  5. Générateurs (instruction yield)
  6. Fichiers