Bibliothèque · Résumé et avis

Fluent Python

De Luciano Ramalho. 1 011 pages sur une seule idée : écrire du Python qui parle la même langue que l'interpréteur.

FR EN
Couverture de Fluent Python, Luciano Ramalho

Fluent Python

Fluent Python: Clear, Concise, and Effective Programming

8.2 /10

« Énorme, dense, exigeant : le livre qui sépare ceux qui écrivent du Python de ceux qui le parlent. »

  • AuteurLuciano Ramalho
  • Édition2e éd. 2022 · 1 011 pages
  • ÉditeurO'Reilly
  • Goodreads4,62/5 · 1 900 notes
  • Fiche~9 min de lecture
Notation du livre sur 5 dimensionsIdées9/10Applicable7/10Lisibilité7/10Actualité9/10Exemples9/10

Le livre qui transforme un dev qui écrit du Python en dev qui pense en Python.

Pourquoi ce livre

Il existe des dizaines de livres pour apprendre Python. Fluent Python n'en fait pas partie : Ramalho suppose que vous écrivez déjà du Python, et s'attaque au problème suivant. Du Python qui marche mais qui sent le Java traduit, le PHP déguisé, le JS recopié. Son angle : vous montrer comment le langage pense, pour que votre code parle la même langue que l'interpréteur.

La préface annonce la méthode : utiliser avant de construire. Vous utilisez les ABCs avant d'en écrire une, vous vivez avec les métaclasses avant d'en créer. Et une mise en garde qui donne le ton : « l'abstraction prématurée est aussi mauvaise que l'optimisation prématurée » (préface).

Les idées qui restent

1L'iceberg : le Python Data Model

Pourquoi len(obj) et pas obj.len() ? Pourquoi obj[clé] déclenche __getitem__ ? Parce que Python repose sur un contrat : les special methods (les « dunders » : __len__, __getitem__...) que l'interpréteur appelle à votre place. « L'iceberg s'appelle le Python Data Model, et c'est l'API qui permet à nos objets de bien jouer avec les fonctionnalités les plus idiomatiques du langage » (p. 3). Implémentez les bons dunders, et votre objet fonctionne avec len(), for, in, le slicing, sans héritage, sans interface déclarée.

Et pourquoi len() n'est pas une méthode ? Réponse de Raymond Hettinger rapportée dans le livre : pour les types natifs, CPython lit directement un champ de la structure C, sans appel de méthode, sans surcharge de dispatch. « Practicality beats purity. » Tout le livre découle de cette logique : le langage privilégie le pratique cohérent sur le pur théorique.

2Deux méthodes, six capacités gratuites

L'exemple d'ouverture, FrenchDeck, est un paquet de 52 cartes en 15 lignes. Il implémente seulement __len__ et __getitem__. Deux méthodes, six capacités gratuites :

  • len(deck) : taille
  • deck[0], deck[-1] : indexation
  • deck[12::13] : slicing (les quatre as)
  • for card in deck : itération
  • card in deck : test d'appartenance
  • sorted(deck, key=…) : tri

Sans héritage, sans interface déclarée. C'est le retour sur investissement du Data Model : implémentez le contrat, le langage fait le reste.

class FrenchDeck:
    def __len__(self):
        return len(self._cards)
    def __getitem__(self, position):
        return self._cards[position]

>>> len(deck)        # 52
>>> deck[12::13]     # les quatre as
>>> Card('Q', 'hearts') in deck   # True

3Les variables sont des étiquettes, pas des boîtes

Le piège Python le plus fréquent vient d'une image mentale fausse. « L'instruction b = a ne copie pas le contenu de la boîte a dans la boîte b. Elle attache l'étiquette b à l'objet qui porte déjà l'étiquette a » (p. 203). D'où le HauntedBus du chapitre 6 : un paramètre par défaut mutable (def __init__(self, passengers=[])) est créé une seule fois et partagé. Les passagers fantômes montés dans un bus apparaissent dans tous les bus créés sans passagers.

4Closures : la fonction emporte son environnement

Une closure, c'est une fonction qui « emporte » avec elle les variables de l'endroit où elle est née, même après que cet endroit a disparu. L'exemple du livre, une moyenne mobile :

def make_averager():
    series = []                       # variable locale de make_averager…
    def averager(value):
        series.append(value)          # …mais averager y accède encore
        return sum(series) / len(series)
    return averager

avg = make_averager()
avg(10); avg(20)                      # 15.0 : series a survécu entre les appels

« Une fonction qui retient les liaisons des variables libres existant quand elle est définie » (p. 314). Le piège que le livre démonte : series.append(...) marche (on mute la liste), mais count += 1 planterait, car réassigner rend la variable locale et masque la capture. Le mot-clé nonlocal count existe exactement pour dire « non, garde la variable du dessus ».

5Les décorateurs et leurs deux temporalités

Un décorateur, c'est cible = decore(cible), rien de plus : une fonction qui en emballe une autre pour lui ajouter un comportement. La démonstration de force du livre, la mémoïsation en une ligne :

@functools.cache                 # une seule ligne ajoutée au-dessus
def fibonacci(n):
    return n if n < 2 else fibonacci(n-1) + fibonacci(n-2)

# fibonacci(30) : 832 040 appels → 31. 12 secondes → 0,0002 seconde.

Le chapitre 9 installe aussi une distinction qui change la lecture du code : le décorateur s'exécute à l'import du module (quand Python lit le fichier), la fonction décorée seulement à l'appel. C'est ce décalage qui permet à un décorateur d'enregistrer une fonction dans une table au chargement, avant même qu'on l'appelle.

6Duck typing, goose typing : la carte des types

Depuis Python 3.8, il y a quatre façons de penser les interfaces, cartographiées sur deux axes : vérification à l'exécution ou statique, typage par structure ou par nom :

  • Duck typing : l'objet a la méthode, donc ça marche. Aucune déclaration. Une classe avec un seul __getitem__ est itérable. À utiliser pour les scripts et le code interne.
  • Goose typing : ABCs + isinstance. Enregistrement explicite, vérification à l'exécution. À utiliser quand les appelants ont besoin d'une garantie à l'exécution.
  • Typage statique : type hints à la Java, vérifiés par mypy/pyright. À utiliser pour les grandes bases de code et les APIs publiques.
  • Static duck typing : typing.Protocol, l'approche de Go : correspondance structurelle vérifiée statiquement, sans héritage. À utiliser pour les libs publiques qui ne veulent pas imposer des ABCs aux utilisateurs.

Le verdict du livre : ces quatre approches sont complémentaires, aucune ne mérite d'être écartée (p. 432). La carte sert à choisir en conscience, pas à choisir un camp.

7yield : l'Iterator pattern intégré au langage

Quand les données ne tiennent pas en mémoire, il faut les produire une à la fois, à la demande. Toute fonction qui contient yield devient un générateur : elle ne calcule rien tant qu'on ne lui demande pas la valeur suivante.

def lire_lignes(chemin):
    with open(chemin) as f:
        for ligne in f:
            yield ligne.strip()      # une ligne à la fois, jamais tout en RAM

for ligne in lire_lignes('fichier_50go.log'):  # marche avec quelques Ko de mémoire
    traiter(ligne)

Précision de vocabulaire que le livre martèle : une fonction retourne une valeur et meurt ; un générateur yield des valeurs et se met en pause entre chacune, reprenant exactement où il s'était arrêté. Là où Java code le design pattern Iterator à la main, Python l'a intégré au langage avec ce seul mot-clé.

8Le GIL, expliqué en dix points

Le chapitre 19 démine le sujet le plus mal compris de Python : un seul thread Python s'exécute à la fois, quel que soit le nombre de cœurs. Mais toutes les fonctions qui font un appel système (I/O disque, réseau, time.sleep) libèrent le GIL. Conséquence : les threads Python sont excellents pour attendre (« Python threads are great at doing nothing », David Beazley, cité p. 700) et inutiles pour le calcul.

Détail peu connu listé au point 6 : beaucoup de fonctions CPU-intensives de NumPy/SciPy et les compressions zlib/bz2 libèrent aussi le GIL, c'est pour ça que le calcul scientifique en threads peut marcher. Pour du CPU intensif en Python pur : plusieurs processus.

Un grand serpent endormi enroulé autour d'un tourniquet, une longue file de petits personnages avec des ordinateurs portables qui attendent en somnolant, un seul personnage court de l'autre côté
Le GIL : un seul tourniquet, gardé par un python qui dort, et une file de threads excellents à ne rien faire.

Trois choses que je ne savais pas avant de le lire

Mon avis, honnêtement

Son truc unique, c'est le fil conducteur. Les autres livres Python empilent des fonctionnalités ; celui-là déroule UNE idée (le Data Model) sur cinq parties. Et les exemples ont des noms : un jeu de cartes FrenchDeck, un bus hanté. Un bus hanté, dans un livre technique. Des années après, on s'en souvient encore.

La critique méritée : 1 011 pages. C'est un marathon, et tout le monde ne finira pas. Les chapitres sur les type hints sont arides, et la partie V (métaprogrammation) concerne peut-être 5 % des lecteurs. Ramalho le sait : il l'a structuré en « cinq livres en un ». Prenez-le comme un livre de chevet de six mois, pas une lecture de vacances.

En 2026, l'IA génère du Python qui marche, rarement du Python qui chante : des getters inutiles, des boucles indexées là où une comprehension suffirait, du threading que le GIL annule en silence. Ce livre, c'est la grille qui fait voir la différence entre du Python et du Java déguisé en Python.

Odilon

Toujours valable en 2026 ?

Deuxième édition de 2022, Python 3.10 : pattern matching et typing moderne couverts. Le projet de GIL optionnel (PEP 703, Python 3.13+) ne change pas les dix points du chapitre 19 pour l'instant : le GIL reste activé par défaut. Les fondamentaux (Data Model, références, closures) ne bougent pas, parce qu'ils sont le langage lui-même.

Pour qui ?

Lisez-le si

  • Vous avez 1-2 ans de Python et vos programmes marchent sans que vous sachiez toujours pourquoi
  • Vous venez de Java, PHP ou JS et votre Python ressemble encore à votre ancien langage
  • Vous relisez du Python généré par IA et voulez reconnaître ce qui n'est pas idiomatique
  • Vous voulez comprendre les __dunders__ au lieu de les copier de Stack Overflow

Passez si

  • Vous débutez en programmation : Python Crash Course d'abord, celui-là dans deux ans
  • Vous cherchez des recettes à coller : c'est un livre de modèle mental, pas un cookbook
  • Vous utilisez Python occasionnellement pour des scripts : le retour sur 1 011 pages ne sera pas là

Pour aller plus loin

Les fondamentaux de ce livre se pratiquent dans le cours Python de ce site. Pour relire du code généré avec un œil critique, voyez Coder avec l'IA. L'équivalent TypeScript du rôle de ce livre est Effective TypeScript, aussi dans cette bibliothèque.

Commentaires (0)

Voir toute la bibliothèque

D'autres fiches arrivent : un livre à la fois, la substantifique moelle seulement.