L'itération est un concept fondamental en Python. Elle désigne l'action d'accéder séquentiellement à chaque élément d'un conteneur selon un ordre prédéfini, comme lors de l'utilisation d'une boucle for.
Objets itérables (Iterable)
Un objet itérable est un objet capable de produire un itérateur. En d'autres termes, c'est un objet qui peut fournir ses éléments un par un. Les types de collections intégrés tels que list, set, dict, tuple et str sont tous itérables. Cela signifie qu'ils peuvent être parcourus avec une boucle for.
- Les objets itérables possèdent généralement une méthode
__iter__permettant de générer un itérateur
Caractéristiques des objets itérables :
- On peut obtenir un itérateur via la fonction
iter() - Ils sont compatibles avec les boucles for, grâce à leur interface d'itérateur
# Parcours d'une liste avec for
ma_liste = [1, 2, 3]
for element in ma_liste:
print(element)
# Parcours d'un tuple avec for
t = (1, 2, 3)
for element in t:
print(element)
# Parcours d'un ensemble avec for
s = {1, 2, 3, 4}
for element in s:
print(element)
# Parcours d'un dictionnaire avec for
mon_dico = {'nom':'Jim', 'age':12}
for cle in mon_dico:
print(cle)
Itérateurs (Iterator)
Un itérateur est un objet implémentant les méthodes __iter__() et __next__(). La première retourne l'itérateur lui-même, la seconde renvoie l'élément suivant de la séquence.
Les itérateurs sont des objets itérables particuliesr :
__next__: Accède aux éléments de l'itérateur- Démarre par le premier élément et se termine au dernier. Une tentative d'accès supplémentaire déclenche l'exception
StopIteration. Les éléments sont consommés après accès.
Caractéristiques des itérateurs :
- Objet mémorisant sa position d'itération
- Parcours linéaire du début à la fin, sans possibilité de recul
- L'élément suivant peut être récupéré manuellement avec
next(), ce qui déclencheStopIterationà la fin
class IterateurPersonnalise:
def __init__(self, elements):
self.elements = elements
self.position = 0
def __iter__(self):
return self
def __next__(self):
if self.position >= len(self.elements):
raise StopIteration
resultat = self.elements[self.position]
self.position += 1
return resultat
# Utilisation de l'itérateur
mon_iterateur = IterateurPersonnalise([1, 2, 3])
for valeur in mon_iterateur:
print(valeur)
it1 = ma_liste.__iter__()
it1
it1.__next__()
it1.__next__()
it1.__next__()
# Tentative d'accès au-delà de la fin déclenche StopIteration
it1.__next__()
Synthèse sur les itérateurs et objets itérables :
- Tous les itérateurs sont itérables, mais l'inverse n'est pas vrai
- Les objets itérables fournissent un itérateur, tandis que les itérateurs permettent l'itération
# Utilisation d'une boucle for avec itérateur
class IterateurNumerique:
def __init__(self, valeurs):
self.valeurs = valeurs
self.compteur = 0
def __iter__(self):
return self
def __next__(self):
if self.compteur >= len(self.valeurs):
raise StopIteration
resultat = self.valeurs[self.compteur]
self.compteur += 1
return resultat
# Instanciation et itération
iterateur = IterateurNumerique([1, 2, 3, 4, 5])
for numero in iterateur:
print(numero)
# Utilisation d'une boucle while
iterateur = IterateurNumerique([1, 2, 3, 4, 5, 6])
it = iter(iterateur)
while True:
try:
print(next(it))
except StopIteration:
break
Avantages des itérateurs
- Efficacité mémoire : Calcul des valeurs sur demande, sans stockage complet en mémoire
- Calcul paresseux : Génération progressive des éléments, utile pour les grands ensembles ou flux infinis
- Interface unifiée : Permet d'itérer sur n'importe quelle structure sans connaître sa nature interne
class IterateurFibonacci:
def __init__(self):
self.premier = 0
self.second = 1
def __iter__(self):
return self
def __next__(self):
resultat = self.premier
self.premier, self.second = self.second, self.premier + self.second
return resultat
# Génération d'une suite infinie
fib_iter = IterateurFibonacci()
# Affichage des 10 premiers nombres
for i, nombre in enumerate(fib_iter):
if i >= 10:
break
print(nombre)