Skip to content

Latest commit

 

History

1,563 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Thinking in Python

Fluency, Types, and Design

A python coiled into an infinity sign, swallowing its own tail

Bruce Eckel

An intermediate-to-advanced book for experienced programmers. It opens with a fast introduction for programmers coming from other languages.

Read the Book Online

ThinkingInPython.com

Download the Book

The latest release, rebuilt from the current book source:

All versions are on the releases page.

Examples and Solutions

Every listing in the book is a real file that runs. You will find it in Examples/, in its chapter's directory, under the name the book gives it. The answers to the exercises are in Solutions/.

Directory What is in it
Examples/ The book's listings, one directory per chapter (Examples/07_Foundations--Classes/), each file named the way the book names it (property_setter.py).
Examples/utils/ Helpers that several chapters import, such as display.py and benchmark.py. Not a chapter.
Solutions/ Worked answers to the exercises, one Markdown file per chapter, numbered to match that chapter's exercise list.
SolutionsCode/ The solution listings extracted to .py files, the same way Examples/ is.
Chapters/ The book itself, one Markdown file per chapter.

The build generates both code trees from Chapters/ and Solutions/, where each listing is a fenced python block whose first line is a # name.py comment. The code you read is therefore the code that runs.

Reading a listing

The file is byte for byte what the book prints. A #: comment holds the output of the statement above it:

c = Circle(10)
print(c.radius)
#: 10
print(c.area)
#: 314.159

The build runs every listing and compares its stdout against these markers, so a marker in the book always says what the code prints.

Working the exercises

Each chapter ends with exercises that name the listing to start from ("Add a method shrink(self, factor) to Circle in property_setter.py"). Copy that file, change it, run it. Then compare with the numbered answer in that chapter's Solutions/ file. Each solution is self-contained: it repeats whatever it needs from the chapter rather than importing it, so you can read or run one on its own.

make sync regenerates Examples/ and SolutionsCode/ from the Markdown, discarding any edits you made there. Experiment in them freely, but keep anything you want to save outside those two trees.

Setup

You'll need to do this to experiment with the examples and exercises.

Install

  1. Clone this repository.
  2. You need a make command. This is preinstalled on Linux and macOS (macOS: install Xcode Command Line Tools if it's missing). For Windows: winget install ezwinports.make
  3. Install uv.
  4. Run uv sync once. This creates .venv and installs the pinned Python (3.15+) and the dev tools automatically.
  5. Run make tools-check to verify the essential tools.

That is everything you need to run and test the examples and the solutions. make doctor diagnoses the two environment problems that bite in practice: a stale uv stuck on an old Python prerelease, and (on Windows) a process holding .venv open.

Type make to see every target. In a terminal it opens a picker instead: arrow keys choose, Enter runs, and ? shows a target's full documentation.

Optional: Building the Book

Building the book itself needs more. make site, make local, and make serve need pandoc on your PATH, make pdf also needs typst, and make prose needs the standalone vale binary. make tools-check-full checks for all of them. See tools/README for details and install links.

Run and test everything

The commands below rebuild build/examples/ and build/solutions/ from the Markdown chapters, so they always test the current book, never a stale copy.

Command What it does
make run Executes every example file and reports failures.
make test Runs the book's pytest examples, the test_*.py files.
make ty Type-checks every example. Must come out clean.
make lint PEP8-lints every example with ruff. Must come out clean.
make solutions-run Executes every extracted solution and reports failures.
make solutions-test Runs the solutions' pytest examples.
make solutions-ty, make solutions-lint The same two checks over build/solutions/.
make solutions-gate Every solutions check at once: exercise numbering, drift, output markers, types, lint, runs, tests.
make gate Every check over both trees. Run this before committing.

A first run also pays for downloading the pinned Python and the dev tools.

To run one example instead of all of them, see Run one example by hand below.

A few examples cannot run unattended because they open a window, wait for input, or loop forever. make run reports those as "Can't run unattended" rather than as failures. tools/data/norun.txt lists them. Run one by hand to watch it work.

make gate runs the solutions checks first, as a prerequisite, so a failure there hides every Chapters/ failure behind it. make sweep runs everything and reports them all instead of stopping at the first. gate also refreshes generated content in place: it rewraps prose to one sentence per line, and it rewrites any #: marker whose listing now prints something else. Expect git diff Chapters/ to show both.

Work on one chapter

make check-ch CH=07 runs the whole code-example gate against one chapter instead of all 47: extract, output markers, listing format, types, lint, tests. CH takes a number or a filename stem. Make this your edit loop. Only make gate catches breakage across chapters.

Run one example by hand

make run-one runs any single example from the repo root and shows its output. F takes the file's name, or as much of its path as you care to type:

make run-one F=deque_timing
make run-one F=Examples/07_Foundations--Classes/property_setter.py

It sets up what the example expects, and prints the commands it stood in for, because those are what you type when make is not at hand:

cd Examples/03_Foundations--Containers
PYTHONPATH=../utils uv run python deque_timing.py

Both lines matter. An example reads its sibling modules and data files by relative path, so it must run from its own chapter directory. About 70 of them also import a shared helper that lives in Examples/utils (from benchmark import report), so that directory has to be on the import path. Miss the second line and Python says:

ModuleNotFoundError: No module named 'benchmark'

In PowerShell the PYTHONPATH line is $env:PYTHONPATH = "../utils"; make run-one prints whichever form fits your shell.

Use uv run python, not a bare python. A python already on your PATH is usually an older release, and these examples use Python 3.15 syntax.


History

I started this book in 2008 and after a few years it kind of drifted to a stop. I think part of the problem was that I wanted to move the design patterns work I had done in Java into Python and even then I was beginning to become uncertain about OOP (The material is still there, translated, but it is preceded by a chapter explaining my OOP misgivings).

I had forgotten about this book but (especially at Pycons) people would occasionally come up to me and mention that they had gotten some value out of it. Because of the condition of the book, which still had a number of examples that were still in Java (!), I found this embarrassing.

In June 2026 I decided to see what the Claude AI could do with it, and in short order it had brought everything up to Python 3.15, with type annotations, passing standards checkers, cleaning up prose, etc. I began going back through my Pycon presentations and blog posts and adding those. At the moment it is in decent shape and you can read it online: https://bruceeckel.github.io/ThinkingInPython/


Edit checklist

This is for my own bookkeeping.

Chapter Edit State
01_Introduction.md
02_Foundations--Tour.md
03_Foundations--Containers.md
04_Foundations--Control_Flow.md
05_Foundations--Functions.md
06_Foundations--Modules_and_Packages.md
07_Foundations--Classes.md
08_Foundations--Static_Types.md
09_Foundations--Class_Attributes.md
10_Foundations--Cleanup.md
11_Techniques--Testing.md
12_Techniques--Data_Classes_as_Types.md
13_Techniques--Pattern_Matching.md
14_Techniques--Decorators.md
15_Techniques--Context_Managers.md
16_Techniques--Comprehensions.md
17_Techniques--Metaprogramming.md
18_Techniques--Performance.md
19_Techniques--Concurrency.md
20_Patterns--Rethinking_Objects.md
21_Patterns--Design_Patterns.md
22_Patterns--Data_Transfer_Objects.md
23_Patterns--Iterators.md
24_Patterns--Singleton.md
25_Patterns--Template_Method.md X
26_Patterns--Surrogate.md X
27_Patterns--Factory.md O
28_Patterns--Function_Objects.md r
29_Patterns--Changing_the_Interface.md
30_Patterns--Observer.md
31_Patterns--State_Machines.md
32_Patterns--Multiple_Dispatching.md
33_Patterns--Visitor.md
34_Patterns--Composite_and_Interpreter.md
35_Patterns--Flyweight.md
36_Patterns--Memento.md
37_Patterns--Pattern_Refactoring.md
38_Patterns--Simulation.md
39_Patterns--Pattern_Catalog.md
40_Functional--Foundations.md
41_Functional--Toolkits.md
42_Functional--Error_Handling.md
43_Functional--Confidence.md
44_Effects--Effect_Management.md
45_Effects--Generators.md
46_Effects--Stateless.md
47_Effects--Stateless_in_Practice.md

About

Fluency, Types, and Design

Resources

Contributing

Stars

226 stars

Watchers

19 watching

Forks

Releases

Packages

Contributors

Languages