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

L'argument par défaut évalué une seule fois, à la définition The default argument evaluated once, at definition

Le défaut d'un paramètre n'est pas recalculé à chaque appel : l'expression tourne une seule fois, quand def s'exécute, et le résultat se range sur la fonction. Un défaut mutable devient alors un état partagé qui survit entre les appels — et un def f(t=time.time()) fige l'instant de sa propre naissance. L'antidote tient en un mot immuable : None. A parameter's default isn't recomputed on each call: the expression runs once, when def executes, and the result is stored on the function. A mutable default then becomes shared state surviving across calls — and def f(t=time.time()) freezes the instant of its own birth. The antidote fits in one immutable word: None.

AudienceAudience
Dev qui a vu le piège du défaut mutable et veut en comprendre la mécanique Dev who has seen the mutable-default trap and wants its mechanics
Format
Self-paced
ChapitresChapters
5
Date
Juil 2026 Jul 2026
≈ 18 min ●○○○ MutabilitéFonctionsÉtat partagé

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

Un défaut est évalué à la définition, jamais à l'appel.A default is evaluated at definition, never at the call.

Au premier numéro, on a croisé def f(x=[]) comme un symptôme : la liste qui ne se vide jamais. On va maintenant le disséquer comme un mécanisme — et découvrir que le piège n'a rien à voir avec les listes. Il tient à un seul décalage : en Python, l'expression par défaut d'un paramètre s'exécute quand la ligne def est lue, une fois pour toutes, pas à chaque appel de la fonction. Venu d'un langage typé, on suppose l'inverse : que le défaut est « la valeur utilisée quand l'argument manque », fraîche à chaque fois. Faux.In the first issue we met def f(x=[]) as a symptom: the list that never empties. Now we dissect it as a mechanism — and find the trap has nothing to do with lists. It comes down to one gap: in Python, a parameter's default expression runs when the def line is read, once and for all, not on each call of the function. Coming from a typed language, you assume the opposite: that the default is 'the value used when the argument is missing', fresh each time. Wrong.

Le défaut n'est pas une liste — c'est un instant figéThe default isn't a list — it's a frozen instant
import time

def stamp(t=time.time()):   # time.time() est appelé UNE fois, ici, à la définition
    return t

# ... trois secondes plus tard ...
stamp()   # renvoie l'instant de la DÉFINITION, pas celui de l'appel
stamp()   # ... et le même instant, encore : le défaut ne se recalcule jamais
Deux moments que Python garde séparésTwo moments Python keeps apart
Temps de la définitionDefinition time
def stamp(...)
time.time() → 1 fois
défaut rangé sur la fonction
Temps de l'appelCall time
stamp()
stamp()
le MÊME défaut, réutilisé

La ligne def n'est pas qu'une déclaration : c'est une instruction qui s'exécute. Elle évalue chaque expression par défaut sur-le-champ, et range le résultat sur l'objet-fonction. L'appel, lui, ne fait que relire ce résultat.The def line isn't just a declaration: it's a statement that runs. It evaluates each default expression on the spot, and stores the result on the function object. The call merely re-reads that result.

Le sous-réflexe du numéroThis issue's sub-reflex

Devant un def f(x=EXPR), demande-toi : EXPR est évaluée maintenant, une fois. Si EXPR produit un objet mutable, tous les appels sans argument le partagent. Si EXPR lit l'heure, une config, un compteur — c'est la valeur au moment de la définition qui est gelée, pour toujours.Facing a def f(x=EXPR), ask yourself: EXPR is evaluated now, once. If EXPR yields a mutable object, every argument-less call shares it. If EXPR reads the clock, a config, a counter — the value at definition time is frozen, forever.

Pourquoi ce numéro clôt le Vol. I.Why this issue closes Vol. I.

Le №01 a posé « un nom lie un objet », le №02 « le type décide de la mutabilité ». Le défaut par argument est le premier lieu où ces deux idées se combinent en un bug de production : un objet, lié une fois, mutable, partagé à l'insu de l'appelant. C'est le pont vers le Vol. II, où l'on demandera pour de bon : qui d'autre tient cette référence ?№01 laid down 'a name binds an object', №02 'the type decides mutability'. The default argument is the first place these two ideas combine into a production bug: one object, bound once, mutable, shared without the caller's knowledge. It's the bridge to Vol. II, where we'll ask for real: who else holds this reference?

🔒

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