54 · Memory management and idiomatic Python
How CPython actually frees memory (reference counting + cyclic GC), the __slots__ trick for memory-hungry classes, and the small habits that separate beginner Python from code that earns LGTM on the first review.
CPython is **reference-counted** — every object carries a counter of how many names point at it; when that counter hits zero the memory is reclaimed immediately, no GC pause needed. A cyclic garbage collector (`gc` module) handles the edge cases where two objects point at each other and their counters never reach zero on their own. Understanding this frees you from cargo-culting `gc.collect()` and helps you reason about **where** your memory actually goes. Pair that understanding with a short list of Pythonic habits and you write code that other engineers trust on first read.
Without this:
Without a mental model of reference counting you'll leak objects inadvertently (by keeping a list that holds the last reference alive), call `gc.collect()` hoping it fixes a 2 GB memory spike that is actually caused by a growing cache, and write loops that look like C code — accumulating technical debt that compounds every time someone else opens the file.
You've covered Python the language — now let's talk about writing it well
You can write correct Python that other engineers find hard to read. You can also write elegant Python that a machine struggles to run at scale. This capstone lesson is about the gap between working and good.
We'll look at three concrete topics:
- CPython's memory model — reference counting, the cyclic GC, and
__slots__ - Size awareness — what does an empty list actually weigh?
- Idiomatic habits — the small conventions that make Python code a pleasure to review
Along the way we'll read the Zen of Python, which is not a joke — it's a one-page design document worth reading at least once in your life as a programmer.
Python (in browser)
Each name binding increments the refcount; each `del` (or scope exit) decrements it. Zero means the memory is freed immediately.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`gc.collect()` returns the number of unreachable objects it found and freed. In normal code you rarely call it manually — Python runs the GC periodically in the background.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`__slots__` removes the per-instance `__dict__`, cutting per-object memory by roughly 40–60%. The trade-off: you can no longer add arbitrary attributes at runtime.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`sys.getsizeof` measures the shallow size of an object — the container's own overhead, not the objects inside it. A tuple is cheaper than a list because it allocates no extra growth buffer.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Four patterns that appear in every Python codebase. The right column is shorter, faster, and what reviewers expect.
Python (in browser)
The Zen of Python is a real design document, not a meme. "Readability counts" has shaped every Python API since 1999. Run this in any Python installation including Pyodide.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python the language is the substrate; the rest of the bootcamp is built on this. Next up: statistics, ML, NLP, deep learning. Everything you'll write from here on rests on the intuitions you've built across these 54 lessons.
What does `del x` actually do in CPython?
- CPython is reference-counted: memory is freed the instant the last reference drops to zero. The cyclic GC (`gc` module) is a fallback for cycles, not the primary mechanism — don't treat it as a normal tool.
- `__slots__` and generators are your two main levers when memory is actually tight (after profiling). `__slots__` removes per-instance `__dict__` overhead for classes instantiated millions of times; generators (chapter 9) produce values lazily instead of materializing a full list.
- The Zen of Python (`import this`) is a real design document, not a meme. "Readability counts" is the single rule that explains most Python API choices. Read it once.
- You are now equipped to write Python that other engineers can read, review, and extend. The idioms — comprehensions, truthiness tests, `.get()`, `enumerate()`, `with` blocks, grouped imports — are the difference between a 2-line review comment and a 40-comment review.
Every line of every ML codebase you'll ever read uses these idioms. PyTorch's `nn.Module` uses `__slots__`. HuggingFace datasets use generators. Production training loops use `with` for everything — file handles, GPU contexts, logging contexts. When you start contributing to an existing ML repo, idiomatic Python is the difference between feedback like 'LGTM' and a 40-comment review.
If you remove it: Code that 'works' but isn't idiomatic is technical debt from day one. Your future colleagues won't trust your PRs and your bugs will hide in plain sight inside loops you wrote like C code. The small habits in this lesson are what let experienced ML engineers read unfamiliar code at speed — they rely on the patterns being predictable.