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

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.

AudienceAudience
Dev d'un langage à interfaces nominales (Java, C#, Go, TS) découvrant le structurel Dev from a nominal-interface language (Java, C#, Go, TS) meeting structural typing
Format
Self-paced
ChapitresChapters
5
Date
Juil 2026 Jul 2026
≈ 18 min ●●○○ Duck typingProtocolesInterfaces

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

Ne demande pas « de quoi hérites-tu ? ». Demande « sais-tu faire ça ? ».Don't ask "what do you inherit from?". Ask "can you do this?".

Nouveau volume, nouvel axe. Les deux premiers demandaient « quel objet, et qui d'autre le tient ? ». Celui-ci demande autre chose : « que sait faire cet objet ? ». En Python, une fonction n'a pas besoin de savoir de quelle classe descend son argument. Elle a besoin qu'il réponde aux appels qu'elle va lui passer. lire_tout ne réclame ni un File, ni une sous-classe de quoi que ce soit : elle appelle .read(), point. Un fichier, un flux mémoire, un objet maison — tout ce qui a une méthode read() convient. L'interface n'est écrite nulle part ; elle est définie, en creux, par ce que la fonction utilise.New volume, new axis. The first two asked 'which object, and who else holds it?'. This one asks something else: 'what can this object do?'. In Python, a function needn't know which class its argument descends from. It needs the argument to answer the calls it's about to make. lire_tout demands neither a File, nor a subclass of anything: it calls .read(), full stop. A file, a memory stream, a home-made object — anything with a read() method fits. The interface is written nowhere; it's defined, in hollow, by what the function uses.

Une fonction, trois types sans lien de parentéOne function, three unrelated types
def lire_tout(source):
    return source.read()          # on ne demande qu'UN comportement : .read()

lire_tout(open("data.txt"))       # un fichier — marche
import io
lire_tout(io.StringIO("salut"))   # un flux en mémoire — marche aussi
# aucune classe commune, aucune déclaration : juste .read() qui répond présent
L'interface appartient à l'appelantThe interface belongs to the caller
File
StringIO
MonObjet
.read()
suffitis enough
lire_tout(source)
ne voit qu'un comportementsees only a behavior

Le protocole « lisible » n'est déclaré par personne. Il existe parce qu'une fonction l'utilise. Tout objet qui répond à .read() le remplit — sans le savoir, sans hériter de rien.The "readable" protocol is declared by no one. It exists because a function uses it. Any object that answers .read() fulfills it — unknowingly, inheriting nothing.

Le réflexe du volumeThe volume's reflex

« Que demande l'appelant — pas de quelle classe hérite le type ? » Quand tu écris une fonction, liste les méthodes que tu appelles sur ton paramètre, pas les types que tu imagines recevoir. Ce sont ces méthodes, et elles seules, qui forment ton vrai contrat."What does the caller need — not which class the type inherits from?" When you write a function, list the methods you call on your parameter, not the types you imagine receiving. Those methods, and only those, form your real contract.

Nominal contre structurel.Nominal versus structural.

Venu de Java, Go ou TypeScript, tu connais l'interface nominale : un type doit déclarer « j'implémente Readable » pour être accepté. Python fait du typage structurel de fait : tu es « lisible » si tu as read(), que tu l'aies annoncé ou non. L'appartenance ne se déclare pas ; elle se constate à l'usage.Coming from Java, Go or TypeScript, you know nominal interfaces: a type must declare 'I implement Readable' to be accepted. Python does de-facto structural typing: you're 'readable' if you have read(), whether you announced it or not. Membership isn't declared; it's observed in use.

🔒

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