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.
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
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.
« 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.
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.