Vol. 5 — № 14
The Python Loop · KiosqueNewsstand
Blog  
Un atelier Python · Édition d'ApprentissageA Python Workshop · Learning Edition

La closure capture la variable, pas la valeur The closure captures the variable, not the value

[lambda: i for i in range(3)] fabrique trois fonctions différentes, mais elles impriment toutes 2 quand on les appelle — jamais 0, 1, 2. Une closure ne capture pas un instantané de la valeur au moment où elle est définie : elle capture la variable elle-même, lue au moment où on l'appelle. La boucle a terminé sa course avant le premier appel ; les trois fonctions lisent la même case, à son état final. [lambda: i for i in range(3)] builds three different functions, but they all print 2 when called — never 0, 1, 2. A closure doesn't capture a snapshot of the value at definition time: it captures the variable itself, read at call time. The loop finishes its run before the first call; all three functions read the same slot, at its final state.

AudienceAudience
Dev qui a créé des callbacks dans une boucle et vu tous imprimer la même valeur Dev who's built callbacks in a loop and watched them all print the same value
Format
Self-paced
ChapitresChapters
5
Date
Juil 2026 Jul 2026
≈ 18 min ●●●○ ClosuresPortéeLiaison tardive

Chapitre 1 en accès libre — la suite (ch. 2 à 5) est réservée. Chapter 1 free to read — the rest (ch. 2–5) is members-only.

01CadrageFraming3 min

Trois lambdas différentes, un seul nombre. Le piège le plus classique des closures.Three different lambdas, one single number. The classic closure trap.

Le numéro précédent a établi LEGB : un nom lu dans une fonction est cherché en Local, puis Enclosing, puis Global, puis Built-in. Une closure est précisément une fonction qui lit un nom dans sa portée Enclosing — une variable définie dans la fonction (ou la boucle) qui l'englobe. Le piège qui ouvre ce numéro est le plus commenté de tout Python : construire une liste de fonctions dans une boucle, une par itération, en espérant que chacune se souvienne de la valeur de la boucle au moment de sa création. Elles s'en souviennent toutes — mais de la même, la dernière.The previous issue established LEGB: a name read inside a function is looked up in Local, then Enclosing, then Global, then Built-in. A closure is precisely a function that reads a name from its Enclosing scope — a variable defined in the function (or loop) that contains it. The trap opening this issue is the most commented-on in all of Python: building a list of functions inside a loop, one per iteration, hoping each remembers the loop's value at the moment of its creation. They all remember — but the same one, the last.

Trois fonctions, trois moments de création, une seule valeur lueThree functions, three moments of creation, one single value read
fonctions = [lambda: i for i in range(3)]

print(fonctions[0]())     # 2 !
print(fonctions[1]())     # 2 !
print(fonctions[2]())     # 2 — les TROIS lambdas impriment la même chose

# et pourtant : "i" valait 0, puis 1, puis 2, à trois moments différents
# de la boucle. On s'attendait à 0, 1, 2. On obtient 2, 2, 2.
Le sous-réflexe du numéroThis issue's sub-reflex

Face à une fonction créée dans une boucle qui lit une variable de la boucle, demande : cette fonction lit-elle la variable au moment où je la crée, ou au moment où je l'appelle ? La réponse, pour Python, est toujours la seconde.Facing a function created inside a loop that reads the loop's variable, ask: does this function read the variable at the moment I create it, or at the moment I call it? For Python, the answer is always the latter.

Ce n'est pas un bug de lambdaIt's not a lambda bug

Le même piège se produit avec def à l'intérieur d'une boucle, avec un callback passé à un widget, avec une closure retournée par une fabrique de fonctions. lambda n'est qu'une syntaxe compacte pour créer une fonction — le comportement de capture est identique partout.The same trap occurs with def inside a loop, with a callback passed to a widget, with a closure returned by a function factory. lambda is just compact syntax for creating a function — the capture behavior is identical everywhere.

🔒

La suite est réservée The rest is members-only

Le premier numéro est libre. Débloque tout The Python Loop — tous les volumes, à vie — pour 5 €, paiement unique. The first issue is free. Unlock all of The Python Loop — every volume, forever — for €5, one-time.

Retour au kiosqueBack to newsstand