Vol. I → IX
The Python Loop · KiosqueNewsstand
Blog  
Le Kiosque · Édition d'Apprentissage The Newsstand · Learning Edition

Une seule tension du modèle objet de Python,
disséquée jusqu'à l'os.
One tension in Python's object model,
dissected to the bone.

Une collection éditoriale pour le développeur qui ne veut pas confondre simple et facile. Un numéro = un mécanisme-clé, disséqué jusqu'à ce que la tension soit nue : quel bug il tient à distance, ce que le dynamisme te laisse porter, et quand ne pas l'employer. On arrête de réciter la syntaxe — on écoute le modèle. Un nom n'est pas une boîte ; c'est une étiquette collée sur un objet. An editorial collection for the developer who refuses to confuse simple with easy. One issue = one key mechanism, dissected until the tension is bare: which bug it keeps at arm's length, what dynamism leaves on your shoulders, and when not to use it. You stop reciting syntax — you listen to the model. Names are not boxes; they are labels stuck onto objects.

Numéros parusIssues out
27
En préparationIn the works
00
À venirForthcoming
00
Les rayonsThe shelves
09 vol.vol.
Vol. I — Noms & objetsNames & objects a = b copie-t-il ?Does a = b copy? · 03 numérosissues
DisponibleAvailable
Vol. 1 · №01 Juil 2026Jul 2026
01
b = a ne copie rien,
il colle une seconde étiquette
b = a copies nothing,
it sticks a second label

Trois lignes que tout le monde écrit le premier jour. On assigne b = a en croyant copier la liste, on modifie « seulement » b — et a a changé aussi. Ce n'est pas un bug : c'est tout le modèle objet de Python qui tient dans un signe égal. Un nom n'est pas une boîte qui contient une valeur ; c'est une étiquette collée sur un objet. Three lines everyone writes on day one. You assign b = a thinking you copied the list, you change 'only' b — and a changed too. It's no bug: it's all of Python's object model fitting inside an equals sign. A name isn't a box that holds a value; it's a label stuck onto an object.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 17 min
NiveauLevel ●○○○
Noms & objetsRéférencesMutabilité
DisponibleAvailable
Vol. 1 · №02 Juil 2026Jul 2026
02
Mutable ou immuable : pourquoi += ment Mutable or immutable: why += lies

Un seul opérateur, deux gestes opposés. x += 1 fabrique un nouvel objet et recolle l'étiquette ; lst += [1] mute la liste sur place. Le signe ne décide de rien — c'est le type de l'objet qui tranche. Et quand un tuple « immuable » contient une liste, la même ligne peut muter l'objet ET lever une exception dans la foulée. One operator, two opposite moves. x += 1 builds a new object and re-sticks the label; lst += [1] mutates the list in place. The sign decides nothing — the object's type does. And when an 'immutable' tuple holds a list, the same line can mutate the object AND raise an exception in one breath.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●○○○
MutabilitéRéférencestuple
DisponibleAvailable
Vol. 1 · №03 Juil 2026Jul 2026
03
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.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●○○○
MutabilitéFonctionsÉtat partagé
Vol. II — Aliasing & copiesAliasing & copies Qui d'autre voit cet objet ?Who else sees this object? · 03 numérosissues
DisponibleAvailable
Vol. 2 · №04 Juil 2026Jul 2026
04
L'aliasing : un objet,
plusieurs noms,
un effet à distance
Aliasing: one object,
many names,
action at a distance

Passer un objet à une fonction ne le copie pas : le paramètre devient un second nom sur le même objet. Muter cet objet en place se voit chez l'appelant ; réassigner le nom local, non. Toute la différence entre une fonction qui rend un service et une qui saccage tes données tient dans cette ligne de partage — muter, ou rebind. Passing an object to a function doesn't copy it: the parameter becomes a second name on the same object. Mutating that object in place shows in the caller; rebinding the local name doesn't. The whole difference between a function that helps and one that wrecks your data sits on that dividing line — mutate, or rebind.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 17 min
NiveauLevel ●●○○
AliasingRéférencesFonctions
DisponibleAvailable
Vol. 2 · №05 Juil 2026Jul 2026
05
copy contre deepcopy : ce qu'une copie copie vraiment copy versus deepcopy: what a copy actually copies

« Copie d'abord » est la parade à l'aliasing — encore faut-il savoir ce qu'on duplique. list(x), x[:], dict(x) clonent le contenant mais partagent encore les éléments : la copie de surface. copy.deepcopy descend récursivement et isole tout, à un prix — et souvent pour rien. Entre les deux, la juste dose se choisit, elle ne se subit pas. 'Copy first' is the counter to aliasing — provided you know what you're duplicating. list(x), x[:], dict(x) clone the container but still share the elements: the shallow copy. copy.deepcopy descends recursively and isolates everything, at a price — often for nothing. Between the two, the right dose is chosen, not suffered.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
CopiesAliasingdeepcopy
DisponibleAvailable
Vol. 2 · №06 Juil 2026Jul 2026
06
Le slicing copie le contenant,
jamais le contenu
Slicing copies the container,
never the content

sous = grille[:] a tout d'une copie franche : le crochet vide dit « tout, en neuf ». C'en est une — d'un seul niveau. Sur une liste de listes, les lignes restent partagées, et un sous[0].append() rejaillit sur l'original. Pire, [[0]*3]*3 fabrique trois noms sur une même ligne. Et l'affectation de tranche a[:] = X ne copie rien : elle mute l'objet en place, sous tous ses alias. sub = grid[:] looks every bit an honest copy: the empty bracket says 'all of it, fresh'. It is one — of a single level. On a list of lists, the rows stay shared, and a sub[0].append() splashes back onto the original. Worse, [[0]*3]*3 makes three names for one row. And slice assignment a[:] = X copies nothing: it mutates the object in place, under all its aliases.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 17 min
NiveauLevel ●●○○
SlicingCopiesAliasing
Vol. III — Le protocole impliciteThe implicit protocol Que demande l'appelant ?What does the caller need? · 03 numérosissues
DisponibleAvailable
Vol. 3 · №07 Juil 2026Jul 2026
07
Duck typing : un objet est ce qu'il sait faire Duck typing: an object is what it can do

« If it walks like a duck and quacks like a duck, it's a duck. » En Python, une fonction ne devrait pas demander de quelle classe tu hérites, mais si tu réponds à l'appel qu'elle va te passer. L'interface appartient au consommateur : implémente les bonnes méthodes, et tu satisfais le protocole sans rien déclarer. Le prix : aucun compilateur ne vérifie ce contrat — il te reste l'AttributeError, au runtime, loin de la faute. 'If it walks like a duck and quacks like a duck, it's a duck.' In Python, a function shouldn't ask which class you inherit from, but whether you answer the call it's about to make. The interface belongs to the consumer: implement the right methods, and you satisfy the protocol without declaring anything. The price: no compiler checks that contract — you're left with AttributeError, at runtime, far from the fault.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
Duck typingProtocolesInterfaces
DisponibleAvailable
Vol. 3 · №08 Juil 2026Jul 2026
08
Les dunders sont le protocole : len(x) appelle x.__len__() The dunders are the protocol: len(x) calls x.__len__()

Le vrai pouvoir de Python n'est pas dans les méthodes que tu nommes, mais dans celles qu'il appelle pour toi. len(x) exécute x.__len__(), x[k] exécute x.__getitem__(k), a + b exécute a.__add__(b). Implémente les bonnes méthodes spéciales, et ton objet se fond dans la syntaxe du langage — pas par héritage, par le modèle de données. Le prix : chaque dunder t'engage à un contrat que le langage suppose tenu. Python's real power isn't in the methods you name, but in the ones it calls for you. len(x) runs x.__len__(), x[k] runs x.__getitem__(k), a + b runs a.__add__(b). Implement the right special methods, and your object melts into the language's syntax — not by inheritance, by the data model. The price: each dunder commits you to a contract the language assumes is upheld.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
Data modelDundersProtocoles
DisponibleAvailable
Vol. 3 · №09 Juil 2026Jul 2026
09
Le contrat __hash__ / __eq__ : l'objet mutable qu'on ne doit jamais hacher The __hash__ / __eq__ pact: the mutable object you must never hash

Un dict cherche une clé en deux temps : hash() choisit le compartiment, == confirme l'identité dedans. Casse l'accord entre les deux — deux objets égaux avec des hash différents — et le dict cherche au bon endroit un objet qui n'y est jamais rangé. C'est pour ça qu'une liste est unhashable : elle mute, et un objet qui mute après avoir été haché se perd dans son propre compartiment. A dict finds a key in two steps: hash() picks the bucket, == confirms identity inside it. Break the deal between the two — two equal objects with different hashes — and the dict searches the right spot for an object that was never filed there. That's why a list is unhashable: it mutates, and an object that mutates after being hashed loses itself in its own bucket.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 19 min
NiveauLevel ●●●○
Data modelHashDict & Set
Vol. IV — Itérateurs & générateursIterators & generators Paresseux, ou épuisé ?Lazy, or exhausted? · 03 numérosissues
DisponibleAvailable
Vol. 4 · №10 Juil 2026Jul 2026
10
L'itérateur : __iter__,
__next__,
StopIteration
The iterator: __iter__,
__next__,
StopIteration

for x in y n'est pas une primitive du langage : c'est iter(y) puis next() en boucle jusqu'à StopIteration. Cette désucre cache une distinction que la plupart des devs ne font jamais — un itérable et un itérateur ne sont pas la même chose. L'un se reparcourt à volonté ; l'autre s'épuise, une fois, et ne le dit à personne. for x in y isn't a language primitive: it's iter(y) then next() in a loop until StopIteration. That desugaring hides a distinction most devs never make — an iterable and an iterator aren't the same thing. One can be walked again and again; the other gets exhausted, once, and tells no one.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
ItérateursData modelfor
DisponibleAvailable
Vol. 4 · №11 Juil 2026Jul 2026
11
Le générateur : yield,
la fonction qui se suspend
The generator: yield,
the function that suspends itself

Une fonction qui contient yield ne s'exécute pas quand tu l'appelles : elle retourne un générateur, un itérateur qui n'a encore rien fait. Chaque next() reprend l'exécution exactement où elle s'était arrêtée — variables locales, position de boucle, tout gelé, sans une seule ligne d'attribut d'instance. Le prix : le corps de la fonction ne s'exécute jamais avant qu'on la tire, pas même la validation que tu croyais immédiate. A function containing yield doesn't run when you call it: it returns a generator, an iterator that has done nothing yet. Each next() resumes execution exactly where it stopped — local variables, loop position, everything frozen, without a single instance-attribute line. The price: the function body never runs before you pull it, not even the validation you assumed was immediate.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
GénérateursyieldItérateurs
DisponibleAvailable
Vol. 4 · №12 Juil 2026Jul 2026
12
La vue qui se consomme : map,
zip,
filter,
et le générateur épuisé
The view that consumes itself: map,
zip,
filter,
and the exhausted generator

map(), zip(), filter() ne sont pas des listes déguisées : ce sont des vues paresseuses, des itérateurs au sens strict du №10, épuisés dès qu'on les a parcourus une fois. Réutiliser l'un d'eux ne lève aucune erreur — il rend juste « vide », en silence, comme s'il n'avait jamais rien contenu. Le seul antidote : list(), et son prix en mémoire. map(), zip(), filter() aren't disguised lists: they're lazy views, iterators in №10's strict sense, exhausted the moment you've walked them once. Reusing one raises no error — it just goes 'empty', silently, as if it never held anything. The one antidote: list(), and its price in memory.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
Itérateursmap/zip/filterGénérateurs
Vol. V — Portée & closuresScope & closures Quand ce nom est-il lu ?When is this name read? · 03 numérosissues
DisponibleAvailable
Vol. 5 · №13 Juil 2026Jul 2026
13
LEGB : la résolution des noms LEGB: name resolution

Lire un nom dans une fonction cherche dans quatre portées, dans un ordre fixe : Local, Enclosing, Global, Built-in. Mais Python décide si un nom est local avant même d'exécuter la moindre ligne — en scannant tout le corps de la fonction à la recherche d'une assignation. Le résultat : lire une variable avant de l'assigner, plus bas dans la même fonction, ne va pas chercher la variable globale du même nom. Ça lève une UnboundLocalError. Reading a name inside a function searches four scopes, in a fixed order: Local, Enclosing, Global, Built-in. But Python decides whether a name is local before running a single line — by scanning the whole function body for an assignment. The result: reading a variable before assigning it, further down in the same function, doesn't fall back to the global variable of the same name. It raises UnboundLocalError.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●○○
PortéeLEGBScoping
DisponibleAvailable
Vol. 5 · №14 Juil 2026Jul 2026
14
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.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●○
ClosuresPortéeLiaison tardive
DisponibleAvailable
Vol. 5 · №15 Juil 2026Jul 2026
15
global & nonlocal : l'explicite contre l'implicite global & nonlocal: the explicit against the implicit

Lire un nom englobant ne demande aucune déclaration — LEGB s'en charge (numéro 13). Le réassigner en demande une : sans mot-clé, Python déclare un nom local tout neuf, et l'original englobant reste intouché. global et nonlocal lèvent cette ambiguïté, chacun pointant vers un scope différent — mais l'un crée silencieusement, l'autre exige que la case existe déjà. Reading an enclosing name needs no declaration — LEGB handles it (issue 13). Reassigning it needs one: without a keyword, Python declares a brand-new local name, and the original enclosing one stays untouched. global and nonlocal lift that ambiguity, each pointing to a different scope — but one creates silently, the other demands the slot already exists.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●○
PortéeClosuresglobalnonlocal
Vol. VI — Le modèle d'attributsThe attribute model D'où vient cet attribut ?Where does this attribute come from? · 03 numérosissues
DisponibleAvailable
Vol. 6 · №16 Juil 2026Jul 2026
16
La recherche d'attribut : instance,
classe,
MRO
Attribute lookup: instance,
class,
MRO

obj.x n'est jamais une simple lecture de case mémoire : c'est une recherche, dans un ordre fixe. Python regarde d'abord le __dict__ de l'instance ; s'il n'y trouve rien, il remonte le __dict__ de la classe, puis celui de chaque classe parente, dans l'ordre du MRO. Une liste posée comme attribut de classe est donc partagée par toutes les instances — jusqu'à ce que l'une d'elles écrive enfin la sienne. obj.x is never a plain memory-slot read: it's a search, in a fixed order. Python first looks at the instance's __dict__; finding nothing there, it climbs the class's __dict__, then each parent class's, in MRO order. A list set as a class attribute is therefore shared by every instance — until one of them finally writes its own.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●○
AttributsMRO__dict__
DisponibleAvailable
Vol. 6 · №17 Juil 2026Jul 2026
17
Les descripteurs & property : self.x qui exécute du code Descriptors & property: self.x that runs code

Le numéro précédent s'arrêtait à un __dict__ qui répond. Mais certains objets trouvés dans un __dict__ de classe ne sont pas des valeurs à retourner : ce sont des descripteurs, qui définissent __get__ et __set__, et transforment un accès en apparence anodin — self.x — en appel de méthode. property en est l'exemple le plus courant ; et un descripteur de donnée passe même avant le __dict__ de l'instance. The previous issue stopped once a __dict__ answered. But some objects found in a class __dict__ aren't values to return: they're descriptors, defining __get__ and __set__, turning an access that looks utterly plain — self.x — into a method call. property is the most common example; and a data descriptor even outranks the instance's own __dict__.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●●
Descripteursproperty__get__
DisponibleAvailable
Vol. 6 · №18 Juil 2026Jul 2026
18
__slots__ : le __dict__ a un coût __slots__: the __dict__ has a cost

Chaque instance porte, par défaut, son propre __dict__ — une table de hachage complète, allouée dynamiquement, prête à accueillir n'importe quel attribut à n'importe quel moment. Ce confort a un prix en mémoire, multiplié par chaque objet créé. __slots__ le supprime : les attributs deviennent des descripteurs à taille fixe. La mémoire économisée se paie en flexibilité perdue. Every instance carries, by default, its own __dict__ — a full hash table, dynamically allocated, ready to welcome any attribute at any moment. That comfort has a memory price, multiplied by every object created. __slots__ removes it: attributes become fixed-size descriptors. The memory saved is paid for in lost flexibility.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●●
__slots__MémoireDescripteurs
Vol. VII — Ressources & exceptionsResources & exceptions Qui garantit le nettoyage ?Who guarantees cleanup? · 03 numérosissues
DisponibleAvailable
Vol. 7 · №19 Juil 2026Jul 2026
19
with : le nettoyage garanti with: guaranteed cleanup

f.close() écrit en dernière ligne d'une fonction a l'air de garantir la fermeture du fichier. Il ne le fait pas : une exception levée plus haut saute directement par-dessus cette ligne, sans jamais l'exécuter. with appelle __exit__ quoi qu'il arrive à l'intérieur du bloc — return anticipé, exception, ou sortie normale — le même contrat que finally, mais porté par l'objet lui-même. f.close() written on a function's last line looks like it guarantees the file gets closed. It doesn't: an exception raised further up jumps straight over that line, never running it. with calls __exit__ no matter what happens inside the block — early return, exception, or normal exit — the same contract as finally, but carried by the object itself.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●○
Context managerswithExceptions
DisponibleAvailable
Vol. 7 · №20 Juil 2026Jul 2026
20
EAFP contre LBYL : l'exception comme flux EAFP versus LBYL: the exception as control flow

Vérifier qu'une clé existe avant de la lire semble plus prudent que d'essayer et de rattraper l'échec. Mais entre la vérification et la lecture s'ouvre un intervalle — le temps qu'un autre thread, un autre processus, ou simplement le disque, change l'état vérifié. Python préfère EAFP : tenter l'opération directement, attraper l'exception si elle survient — sans jamais laisser cet intervalle s'ouvrir. Checking that a key exists before reading it looks more careful than trying and catching the failure. But between the check and the read opens a gap — time enough for another thread, another process, or simply the disk, to change the state just checked. Python prefers EAFP: attempting the operation directly, catching the exception if it happens — never leaving that gap open.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 18 min
NiveauLevel ●●●○
ExceptionsEAFPtry/except
DisponibleAvailable
Vol. 7 · №21 Juil 2026Jul 2026
21
finally,
return et le générateur qui lève
finally,
return,
and the generator that raises

with garantissait le nettoyage ; l'except précis évitait d'avaler un vrai bug. Reste une dernière subtilité : que se passe-t-il quand finally et return se disputent la dernière parole dans une même fonction ? Et quand un générateur, jamais épuisé jusqu'au bout, tient encore un fichier ouvert — qui referme sa ressource, et comment ? with guaranteed cleanup; a precise except avoided swallowing a real bug. One last subtlety remains: what happens when finally and return both compete for the last word in the same function? And when a generator, never fully exhausted, is still holding a file open — who closes its resource, and how?

PubliéPublished ~ 5 chap.
LectureRead time ≈ 19 min
NiveauLevel ●●●●
finallyGénérateursGeneratorExit
Vol. VIII — La concurrence & le GILConcurrency & the GIL Qui détient le GIL ?Who holds the GIL? · 03 numérosissues
DisponibleAvailable
Vol. 8 · №22 Juil 2026Jul 2026
22
Le GIL : pourquoi deux threads ne calculent pas en parallèle The GIL: why two threads don't compute in parallel

Lancer deux threads pour accélérer un calcul semble une évidence — sur un CPU à plusieurs cœurs, ils devraient se partager le travail. Pourtant, en Python, un seul thread exécute du bytecode à la fois. Le GIL sérialise le calcul ; seule l'attente — un fichier, un réseau, un timer — libère vraiment un cœur pour un autre thread. Spinning up two threads to speed up a computation looks obvious — on a multi-core CPU, they should split the work. Yet in Python, only one thread executes bytecode at a time. The GIL serializes computation; only waiting — a file, a network call, a timer — actually frees a core for another thread.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 19 min
NiveauLevel ●●●○
GILThreadingConcurrence
DisponibleAvailable
Vol. 8 · №23 Juil 2026Jul 2026
23
asyncio : un seul thread,
coopératif
asyncio: a single thread,
cooperative

Le GIL libère un thread pendant l'attente réseau — mais un seul thread suffit, du moment qu'il sait rendre la main de lui-même. asyncio construit exactement ça : une boucle d'événements qui exécute des milliers de tâches en attente sans jamais ouvrir un seul thread supplémentaire. Le prix : un seul appel bloquant, oublié dans une coroutine, gèle toute la boucle d'un coup. The GIL frees a thread during a network wait — but a single thread is enough, as long as it knows how to hand back control on its own. asyncio builds exactly that: an event loop running thousands of waiting tasks without ever opening a single extra thread. The price: one blocking call, forgotten inside a coroutine, freezes the entire loop at once.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 20 min
NiveauLevel ●●●●
asyncioCoroutinesEvent loop
DisponibleAvailable
Vol. 8 · №24 Juil 2026Jul 2026
24
La coroutine jamais attendue The coroutine that's never awaited

Une coroutine est un objet en attente, pas un calcul en cours — le n°23 l'a montré. La conséquence la plus silencieuse de cette mécanique : coro() sans await ne s'exécute jamais, sans la moindre erreur bruyante. Et une tâche créée avec create_task, sans référence gardée quelque part, peut disparaître avant même d'avoir eu la chance de tourner. A coroutine is a waiting object, not a computation in progress — issue №23 showed that. The most silent consequence of that mechanic: coro() without await never runs, with no loud error at all. And a task created with create_task, with no reference kept anywhere, can vanish before it ever gets the chance to run.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 19 min
NiveauLevel ●●●●
asyncioCoroutinesTasks
Vol. IX — Le coût du dynamismeThe cost of dynamism Connais-tu le coût, ou l'imagines-tu ?Do you know the cost, or guess it? · 03 numérosissues
DisponibleAvailable
Vol. 9 · №25 Juil 2026Jul 2026
25
Comptage de références & cycles Reference counting & cycles

Le n°24 a mentionné une référence faible, sans expliquer ce qui distingue une référence forte. La réponse ouvre le dernier volume de la série : chaque objet Python porte un compteur de références, et meurt à l'instant précis où ce compteur atteint zéro — sauf quand deux objets se référencent mutuellement, et qu'aucun compteur ne redescend jamais à zéro tout seul. Issue №24 mentioned a weak reference, without explaining what sets a strong reference apart. The answer opens the series' final volume: every Python object carries a reference count, and dies at the exact instant that count hits zero — except when two objects reference each other, and no count ever drops to zero on its own.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 20 min
NiveauLevel ●●●●
RefcountGarbage collector__del__
DisponibleAvailable
Vol. 9 · №26 Juil 2026Jul 2026
26
Tout est objet,
tout coûte
Everything is an object,
everything costs

Le Vol. I a posé is contre == sans jamais expliquer pourquoi a is b « marche » parfois. La réponse tenait dans ce numéro : CPython pré-alloue un cache de petits entiers et interne certaines chaînes au démarrage. a is b n'est vrai par coïncidence que pour les valeurs qui tombent dans ce cache — et se brise, sans prévenir, dès qu'on en sort. Vol. I posed is versus == without ever explaining why a is b sometimes 'works'. The answer was waiting in this issue: CPython preallocates a small-int cache and interns certain strings at startup. a is b is only true by coincidence for values that fall inside that cache — and breaks, without warning, the moment you step outside it.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 19 min
NiveauLevel ●●●○
is vs ==InterningCPython
DisponibleAvailable
Vol. 9 · №27 Juil 2026Jul 2026
27
Le prix de la recherche dynamique The price of dynamic lookup

Le Vol. VI a montré comment obj.attr cherche — instance, classe, MRO. Ce dernier numéro chiffre ce que cette recherche coûte réellement, dans la boucle la plus chaude d'un programme, et montre où la mettre en cache. La boucle de la série se referme ici : le dynamisme n'a jamais été gratuit, seulement invisible. Vol. VI showed how obj.attr searches — instance, class, MRO. This final issue puts a number on what that search actually costs, in a program's hottest loop, and shows where to cache it. The series' loop closes here: dynamism was never free, only invisible.

PubliéPublished ~ 5 chap.
LectureRead time ≈ 21 min
NiveauLevel ●●●●
PerformanceAttribute lookup__slots__
Mot de l'éditeurFrom the editor

Pas une syntaxe. Un modèle. Not a syntax. A model.

Le piège, en apprenant Python, c'est de prendre la simplicité pour de la facilité — d'écrire b = a, def f(x=[]), une liste qu'on tranche, sans voir la tension que chaque facilité te laisse porter au runtime. Chaque numéro dissèque une seule tension : noms et références, mutabilité, protocoles implicites, itération paresseuse, coût du dynamisme. Le bug qu'on tient à distance d'abord, le prix ensuite, et le contre-exemple — quand ne pas l'employer. The trap, learning Python, is mistaking simple for easy — writing b = a, def f(x=[]), a list you slice, without seeing the tension each convenience leaves on your shoulders at runtime. Each issue dissects a single tension: names and references, mutability, implicit protocols, lazy iteration, the cost of dynamism. The bug you keep at bay first, the price next, and the counter-example — when not to use it.

La règle tacite : un nom n'est pas une boîte qui contient une valeur ; c'est une étiquette collée sur un objet. Python ne te refuse presque rien — il exécute, et te fait confiance pour tenir l'invariant qu'aucun compilateur ne vérifie. Comprends ce que le dynamisme te coûte, et tu cesses de lutter contre le runtime : tu l'écoutes. The unspoken rule: a variable is not a box that holds a value; it is a label stuck onto an object. Python refuses you almost nothing — it runs, and trusts you to hold the invariant no compiler will check. Understand what dynamism costs you, and you stop fighting the runtime: you listen to it.