Maîtriser les itérateurs Python : fonctionnement et création des vôtres
Itérateurs Python
Découvrez comment fonctionnent les itérateurs Python, comment les parcourir avec des boucles for ou la fonction next(), et comment créer des itérateurs personnalisés ou infinis en utilisant le protocole d'itérateur.
Vidéo : Itérateurs Python
Itérateurs en Python
Les itérateurs sont omniprésents en Python. Ils sous-tendent les boucles for, les compréhensions de liste, les générateurs et de nombreuses structures de données intégrées, travaillant souvent en coulisses.
Un itérateur est simplement un objet qui produit des données un élément à la fois. En Python, tout objet qui implémente les méthodes __iter__() et __next__() est considéré comme un itérateur.
Quand un objet peut fournir un itérateur, on l'appelle itérable. La plupart des conteneurs intégrés — listes, tuples, chaînes, dictionnaires — sont itérables. La fonction intégrée iter() appelle la méthode __iter__() d'un objet pour obtenir un itérateur.
Parcourir un itérateur
Vous pouvez faire avancer manuellement un itérateur avec la fonction next(). Une fois l'itérateur épuisé, StopIteration est levée.
# définir une liste
my_list = [4, 7, 0, 3]
# obtenir un itérateur en utilisant iter()
my_iter = iter(my_list)
# itérer à travers en utilisant next()
# Sortie : 4
print(next(my_iter))
# Sortie : 7
print(next(my_iter))
# next(obj) est identique à obj.__next__()
# Sortie : 0
print(my_iter.__next__())
# Sortie : 3
print(my_iter.__next__())
# Ceci lèvera une erreur, plus d'éléments
next(my_iter)
Sortie
4 7 0 3 Traceback (most recent call last): File "<string>", line 24, in <module> next(my_iter) StopIteration
Une façon plus naturelle d'itérer est d'utiliser une boucle for, qui gère automatiquement le cycle de vie de l'itérateur.
>>> for element in my_list:
... print(element)
... 4 7 0 3
Comment la boucle for fonctionne avec les itérateurs
La boucle for se traduit internement en :
for element in iterable:
# faire quelque chose avec element
Ce qui est équivalent à la logique suivante :
# créer un objet itérateur depuis cet itérable
iter_obj = iter(iterable)
# boucle infinie
while True:
try:
# obtenir l'élément suivant
element = next(iter_obj)
# faire quelque chose avec element
except StopIteration:
# si StopIteration est levée, sortir de la boucle
break
Cela montre que la boucle for est essentiellement une boucle infinie qui repose sur le protocole d'itérateur et l'exception StopIteration pour se terminer.
Construire des itérateurs personnalisés
Créer un itérateur depuis zéro est simple : implémentez __iter__() pour retourner l'instance de l'itérateur (souvent self) et __next__() pour produire la valeur suivante ou lever StopIteration quand fini.
Voici un exemple qui produit les puissances successives de deux jusqu'à un exposant maximum spécifié par l'utilisateur.
class PuissanceDeux:
"""Itérateur qui produit les puissances de deux."""
def __init__(self, max=0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
# créer un objet
nombres = PuissanceDeux(3)
# créer un itérable depuis l'objet
i = iter(nombres)
# Utiliser next pour aller à l'élément suivant
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
Sortie
1 2 4 8 Traceback (most recent call last): File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module> print(next(i)) File "<string>", line 18, in __next__ raise StopIteration StopIteration
Utiliser une boucle for avec l'itérateur personnalisé est tout aussi simple :
>>> for i in PuissanceDeux(5):
... print(i)
... 1 2 4 8 16 32
Itérateurs infinis Python
Les itérateurs peuvent être non bornés. La fonction intégrée iter() accepte un callable et une valeur sentinelle : elle appelle répétitivement la fonction jusqu'à ce que la valeur retournée égale la sentinelle. Par exemple :
>>> int()
0
>>> inf = iter(int, 1)
>>> next(inf)
0
>>> next(inf)
0
Puisque int() retourne toujours 0, iter(int, 1) ne voit jamais la sentinelle, produisant un itérateur infini.
Vous pouvez aussi créer votre propre itérateur infini, comme un qui produit tous les nombres impairs :
class IterInfini:
"""Itérateur infini qui retourne les nombres impairs successifs."""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
Exemple d'exécution :
>>> a = iter(IterInfini())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7
Quand vous travaillez avec des itérateurs infinis, fournissez toujours une condition de terminaison pour éviter les boucles infinies.
Les itérateurs sont efficaces en mémoire car ils produisent les éléments à la demande. Vous pouvez théoriquement générer une séquence non bornée — comme tous les nombres impairs — sans stocker l'ensemble complet.
Pour une façon plus simple de créer des itérateurs, explorez Les générateurs Python avec yield.
Python
- Maîtriser les types de données Python : Guide pratique
- Maîtriser les opérateurs Python : Guide complet
- Maîtriser l'instruction pass en Python : Guide pratique
- Maîtriser les arguments de fonctions Python : Positionnels, nommés et paramètres par défaut
- Maîtriser les dictionnaires Python : création, manipulation et techniques avancées
- Les fermetures Python expliquées : comment les fonctions imbriquées capturent les variables
- Maîtriser Python datetime : guide pratique pour les dates, heures et fuseaux horaires
- Maîtriser time.sleep() en Python : Bonnes pratiques, multithreading et exemples réels
- Python : Aperçu - Langage de haut niveau, lisible, interactif et orienté objet