ProgrammationDéveloppeur Backend Python

Comment fonctionne la boucle for-in en Python ? Quelle infrastructure est fournie pour soutenir ce mécanisme, et que se passe-t-il "sous le capot" lorsque nous itérons sur un objet personnalisé ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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.

Question piège.

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)

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


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.