for n'est pas une boucle native — c'est un while qui attrape une exception.for isn't a native loop — it's a while catching an exception.
Le Vol. III a posé le principe : la syntaxe désucre en dunders, cherchés sur le type. Ce volume applique ce même principe à un axe qu'on n'avait pas encore touché — le temps. for x in y appelle d'abord y.__iter__() pour obtenir un itérateur, puis appelle __next__() sur ce résultat, encore et encore, jusqu'à ce qu'il lève StopIteration. Cette exception n'est pas une erreur : c'est le signal normal, attendu, de fin de parcours. La boucle for n'est qu'une façade élégante sur ce protocole en deux temps — obtenir un itérateur, puis le tirer jusqu'à épuisement.Vol. III established the principle: syntax desugars into dunders, looked up on the type. This volume applies that same principle to an axis we hadn't touched yet — time. for x in y first calls y.__iter__() to get an iterator, then calls __next__() on that result, again and again, until it raises StopIteration. That exception isn't an error: it's the normal, expected signal that the walk is done. The for loop is just an elegant façade over this two-step protocol — get an iterator, then pull it until exhausted.
for x in y: corps(x) # désucré : it = iter(y) # y.__iter__() -> obtient un itérateur while True: try: x = next(it) # it.__next__() -> une valeur, ou lève StopIteration except StopIteration: break # la boucle s'arrête PROPREMENT sur cette exception corps(x)
Chaque fois que tu écris for, demande : l'objet que je parcours produit-il un itérateur frais à chaque appel de iter(), ou EST-il déjà l'itérateur ? La réponse change tout pour un second passage.Every time you write for, ask: does the object I'm walking produce a fresh iterator on each call to iter(), or IS it already the iterator? The answer changes everything for a second pass.
C'est le cas le plus visible en Python où une exception sert de mécanisme de contrôle normal, pas d'erreur — le for l'attrape en silence et s'arrête. Laisser StopIteration s'échapper ailleurs que d'un __next__ est en revanche une faute : dans un générateur, depuis Python 3.7 (PEP 479), elle est convertie en RuntimeError.It's the most visible case in Python where an exception serves as a normal control mechanism, not an error — for catches it silently and stops. Letting StopIteration escape from anywhere but a __next__ is however a mistake: inside a generator, since Python 3.7 (PEP 479), it is converted into a RuntimeError.