Contexte : Le concept d'itérabilité est apparu dans Python pour unifier le travail avec des collections : listes, dictionnaires, ensembles, etc. Tout objet pouvant être parcouru à l'aide d'une boucle for est considéré comme iterable. Cela est réalisé à travers certains méthodes magiques.
Problème : Python exige certains protocoles pour un fonctionnement correct des boucles et fonctions liées aux séquences. Si l'utilisateur n'implémente pas correctement ces protocoles dans sa classe, les mécanismes standard (for, list(), sum(), etc.) ne fonctionneront pas ou se comporteront de manière inattendue.
Solution :
Un objet est iterable s'il implémente la méthode __iter__. Un itérateur est celui qui a une méthode __next__ et __iter__ qui retourne self. En général, l'objet renvoyé par __iter__ est un itérateur, mais ce n'est pas obligatoire. Exemple :
class MyRange: def __init__(self, start, end): self.start = start self.end = end def __iter__(self): self.current = self.start return self def __next__(self): if self.current < self.end: val = self.current self.current += 1 return val raise StopIteration for x in MyRange(1, 4): print(x) # 1, 2, 3
Caractéristiques clés :
__iter__.__next__ et __iter__ (retournant self).__iter__ est efficace si plusieurs passages indépendants sur la collection sont nécessaires.La méthode next est-elle obligatoire pour tout objet iterable ?
Non. Pour un objet iterable, seule __iter__ est nécessaire, retournant un itérateur. __next__ n'est mis en œuvre que par l'itérateur lui-même. Par exemple, un list n'a pas de méthode __next__, mais il est iterable : son __iter__ retourne une instance d'itérateur.
lst = [1, 2, 3] print(hasattr(lst, '__next__')) # False
Un objet peut-il être un itérateur à lui seul ?
Oui, s'il implémente les deux méthodes — __iter__ et __next__.
Peut-on créer plusieurs itérateurs avec un état indépendant pour une même collection ?
Oui, si __iter__ retourne à chaque fois un nouvel objet itérateur.
class MyList: def __init__(self, data): self.data = data def __iter__(self): return iter(self.data)
__next__ sans __iter__ (ou vice versa).Cas négatif : La classe de l'itérateur stocke l'état (par exemple, l'index actuel) au niveau de la classe, et non de l'instance, ce qui casse les parcours parallèles. Avantages :
Cas positif :
Chaque itérateur stocke son état dans l'instance créée dans __iter__.
Avantages :