Library · Reading notes

Fluent Python

By Luciano Ramalho. 1,011 pages on a single idea: writing Python that speaks the same language as the interpreter.

FR EN
Fluent Python book cover, Luciano Ramalho

Fluent Python

Fluent Python: Clear, Concise, and Effective Programming

8 /10

« Huge, dense, demanding: the book that separates those who write Python from those who speak it. »

  • AuthorLuciano Ramalho
  • Edition2e éd. 2022 · 1 011 pages
  • PublisherO'Reilly
  • Goodreads4,62/5 · 1 900 ratings
  • This page~9 min read
Book rating across 5 dimensionsIdeas9/10Practical7/10Readability7/10Aged well9/10Examples9/10

The book that turns a dev who writes Python into a dev who thinks in Python.

Why this book

There are dozens of books for learning Python. Fluent Python is not one of them: Ramalho assumes you already write Python, and tackles the next problem. Python that works but smells like translated Java, disguised PHP, copy-pasted JS. His angle: showing you how the language thinks, so your code speaks the same language as the interpreter.

The preface announces the method: use before you build. You use ABCs before writing one, you live with metaclasses before creating any. And a warning that sets the tone: "Premature abstraction is as bad as premature optimization" (preface).

The ideas that stay

1The iceberg: the Python Data Model

Why len(obj) and not obj.len()? Why does obj[key] trigger __getitem__? Because Python rests on a contract: the special methods (the "dunders": __len__, __getitem__...) that the interpreter calls for you. "The iceberg is called the Python Data Model, and it is the API that we use to make our own objects play well with the most idiomatic language features" (p. 3). And why isn't len() a method? Raymond Hettinger's answer, quoted in the book: for built-in types, CPython reads a C struct field directly, with no method call. "Practicality beats purity." The whole book flows from that logic: the language favors consistent practicality over theoretical purity.

2Two methods, six capabilities for free

The opening example, FrenchDeck, is a 52-card deck in 15 lines. It implements only __len__ and __getitem__. As a result: len(deck), deck[0], slicing like deck[12::13] (the four aces), the for loop, the in operator and sorted() all work, with no inheritance and no declared interface. That's the return on investment of the Data Model: implement the contract, the language does the rest.

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

>>> len(deck)        # 52
>>> deck[12::13]     # the four aces
>>> Card('Q', 'hearts') in deck   # True

3Variables are labels, not boxes

The most common Python trap comes from a wrong mental image. "The b = a statement does not copy the contents of box a into box b. It attaches the label b to the object that already has the label a" (p. 203). Hence chapter 6's HauntedBus: a mutable default parameter (def __init__(self, passengers=[])) is created once and shared by every instance built without arguments. Ghost passengers from one bus haunt all the buses created without passengers.

4Closures: the function carries its environment

make_averager() returns a function computing a running average. The series list is a local variable of make_averager, yet the returned function still accesses it long after. That's a closure: "a function that retains the bindings of the free variables that exist when the function is defined" (p. 314). A subtlety the book takes apart: reassigning (count += 1) breaks the closure, because assignment makes the variable local. The nonlocal keyword exists for exactly this.

5Decorators and their two timelines

A decorator is target = decorate(target), nothing more. But chapter 9 installs a distinction that changes how you read code: decorators run at module import, decorated functions run when called. And the showcase: naive recursive fibonacci(30) calls fibonacci(1) 832,040 times (12 seconds); with @functools.cache, one line above the definition, 31 calls and 0.00017 seconds.

6Duck typing, goose typing: the Typing Map

Since Python 3.8 there are four ways to think about interfaces, which the book maps along two axes: runtime vs static checking, structural vs name-based typing. Classic duck typing (the object has the method, so it works: the Vowels class with a single __getitem__ is iterable), goose typing (ABCs + isinstance), static typing (Java-style type hints), and static duck typing (typing.Protocol, Go's approach). The book's verdict: these four approaches are complementary, and none deserves to be dismissed (p. 432). The map is there to help you choose deliberately: duck typing for a script, Protocol for a public library, ABCs when you need runtime checks.

7yield: the Iterator pattern built into the language

When data doesn't fit in memory, you need to produce items one at a time, on demand. Where Java implements the Iterator design pattern by hand, Python built it in: any function containing yield becomes a generator factory. A vocabulary precision the book hammers: a function returns a value, a generator yields values. The lazy version of the Sentence class (via re.finditer) only reads the next word when you ask for it.

8The GIL, explained in ten points

Chapter 19 defuses Python's most misunderstood topic: only one Python thread executes at a time, regardless of CPU cores. But every function that makes a syscall (disk I/O, network, time.sleep) releases the GIL. Consequence: Python threads are excellent at waiting ("Python threads are great at doing nothing", David Beazley, quoted p. 700) and useless for computation. A lesser-known detail from point 6: many CPU-intensive NumPy/SciPy functions and the zlib/bz2 compressors also release the GIL, which is why threaded scientific computing can work. For CPU-intensive pure Python: multiple processes.

Three things I didn't know before reading it

My take, honestly

What makes the book unique is its single thread. Other Python books list features; this one unrolls one idea (the Data Model) across five parts, and every chapter confirms it. The examples have names (FrenchDeck, HauntedBus) you remember years later.

The deserved criticism: 1,011 pages is a marathon, and not everyone will finish. The type-hint chapters (8 and 15) are dry. Part V (metaprogramming) concerns maybe 5% of readers. Ramalho knows it: he structured the book as "five books in one", to be read by parts. Treat it as a six-month bedside book, not a one-week read.

In 2026, AI generates Python that works, rarely Python that's idiomatic: useless getters and setters, index-based loops where a comprehension would do, threading where the GIL cancels it out. Fluent Python is the grid that lets you see the difference between Python and Java translated into Python.

Odilon

Still relevant in 2026?

Second edition from 2022, covering Python 3.10: pattern matching and modern typing are in. The optional-GIL project (PEP 703, Python 3.13+) doesn't change chapter 19's ten points yet: the GIL remains on by default. The fundamentals (Data Model, references, closures) don't move, because they are the language itself.

Who is it for?

Read it if

  • You have 1-2 years of Python and your programs work without you always knowing why
  • You come from Java, PHP or JS and your Python still looks like your old language
  • You review AI-generated Python and want to spot what isn't idiomatic
  • You want to understand the __dunders__ instead of copying them from Stack Overflow

Skip it if

  • You're new to programming: Python Crash Course first, this one in two years
  • You're looking for recipes to paste: this is a mental-model book, not a cookbook
  • You use Python occasionally for scripts: the return on 1,011 pages won't be there

For going further

The fundamentals practiced in this book pair with the Python course on this site. For reviewing AI-generated code with a critical eye, see Coding with AI. The TypeScript equivalent of this book's role is Effective TypeScript, also in this library.

Comments (0)

Browse the whole library

More book notes coming: one book at a time, the marrow only.