La boucle for-in en Python est mise en œuvre via le protocole d'itération, basé sur deux méthodes spéciales : __iter__() et __next__(). Lorsque la boucle commence, Python appelle iter(obj) (cherche la méthode __iter__). Si un objet itérateur est retourné, dans lequel __next__() est défini, la boucle commence à appeler cette méthode pour obtenir chaque élément suivant.
Si l'élément est retourné avec succès - l'itération continue. Lorsque l'exception StopIteration est levée, la boucle se termine.
Exemple d'itérateur personnalisé :
class Counter: def __init__(self, low, high): self.current = low self.high = high def __iter__(self): return self def __next__(self): if self.current > self.high: raise StopIteration else: self.current += 1 return self.current - 1 for num in Counter(1, 3): print(num) # Affichera 1, 2, 3
Subtilité : De nombreuses structures standard de Python mettent en œuvre le protocole de l'itérateur ; vous pouvez facilement rendre vos objets similaires.
Peut-on utiliser la boucle for-in avec n'importe quel objet Python ? Quelle est la différence entre un objet itérable et un itérateur ?
Réponse : Non, la boucle for-in exige que l'objet soit itérable, c'est-à-dire qu'il implémente la méthode __iter__() qui retourne un itérateur (un objet avec une méthode __next__()). L'itérateur se retourne lui-même via __iter__(), tandis que l'objet itérable ne le fait pas.
Exemple :
lst = [1, 2, 3] iterator = iter(lst) print(hasattr(lst, '__iter__')) # True print(hasattr(iterator, '__next__')) # True (itérateur) print(hasattr(lst, '__next__')) # False (pas un itérateur)
Histoire
Projet : Traitement de gros fichiers.
Problème : Dans le projet, ils ont essayé de répéter le passage sur un objet de fichier (itération sur les lignes d'un fichier) deux fois sans ouvrir explicitement un nouveau fichier - et lors de la deuxième itération, ils n'ont obtenu aucune ligne (le pointeur étant déjà à la fin du fichier !).
Histoire
Projet : Intégration de sa propre classe de collection avec un framework.
Problème : La classe n'a mis en œuvre que
__getitem__, mais pas__iter__, et n'était pas compatible avec les générateurs et les boucles standards (for). Cela a cassé des bibliothèques tierces s'attendant à un itérateur.
Histoire
Projet : Utilisation de map/filter sur des collections personnalisées.
Problème : Sa propre classe de liste n'a pas mis en œuvre
__iter__et__next__, et s'est révélée incompatible avec de nombreuses fonctions standard de Python, ce qui s'est manifesté seulement après des tests d'intégration et a nécessité une réécriture significative.