Python from First PrinciplesPost 19 of 20 · 20 of 20 written
- How to use this guide
- 01What Python actually is
- 02Names, objects and references
- 03Built-in types and what they cost
- 04Control flow and expressions
- 05Functions in depth
- 06Iteration and generators
- 07Classes and the data model
- 08Context managers and exceptions
- 09Modules, packages, imports and environments
- 10Type hints and Pydantic
- 11The performance model
- 12Concurrency and parallelism
- 13NumPy: the array model everything else copies
- 14Data and serialization
- 15PyTorch mental model
- 16AI systems engineering in Python
- 17Tooling, debugging and testing
- 18Asking the right questions
- 19Roadmap and build-to-learn projects
- 20Glossary and resources
19. Roadmap and build-to-learn projects
Python · 19 of 202 min readOct 2026
Python · Post 19 of 202 min readOct 2026
Learn by building small versions of the systems you will use; each project forces one part of this guide into your hands. Move to the next phase only when you pass its exit check, and skip phases where you are already fluent.
- Foundations (Parts 1–4)
- Word-frequency CLI: read a text file, count tokens with
Counter, print the top k, and handle encoding errors. - Rewrite it as a generator pipeline that streams a 1 GB file in constant memory.
- Exit check: you can draw names and objects to explain every output in the aliasing and mutable-default examples of Part 2.
- Word-frequency CLI: read a text file, count tokens with
- Functions, iteration and classes (Parts 5–8)
- A small library with
@retryand@timeddecorators, plus tests. - A dataset class over a JSONL file with
__len__,__getitem__and__iter__, plus abatched()generator. - A tokenizer: character-level first, then byte-pair encoding trained on a text file, with an encode-decode round-trip test.
- Exit check: you can say which special method any line of code calls.
- A small library with
- Packaging and types (Parts 9–10)
- Turn the work above into an installable package: src layout,
pyproject.toml, uv, ruff, mypy, pytest and pre-commit. - Exit check: a fresh clone runs
uv syncthenuv run pytestwith everything green.
- Turn the work above into an installable package: src layout,
- Numerics (Parts 11 and 13)
- Implement softmax, cross-entropy, a linear layer and scaled dot-product attention in NumPy, asserting the shape after every line.
- Brute-force semantic search over 10,000 embeddings. Profile a loop version against the vectorized version.
- Exit check: you can state the output shape of any broadcasting expression before running it.
- Autograd and PyTorch (Part 15)
- A scalar autograd engine in about 100 lines (Karpathy’s micrograd is the model), then train a tiny MLP with it.
- The same MLP in PyTorch on MNIST. Introduce each bug from the Part 15 table on purpose and observe its signature.
- A small character-level GPT in the style of nanoGPT, trained on a small corpus.
- Exit check: you can explain what
backward()does to.gradand whyzero_gradexists.
- AI systems (Parts 12, 14, 16 and 17)
- Async batch classifier: 1,000 texts through an LLM API with a semaphore, timeouts, retries, Pydantic-validated output, JSONL results and a cost report.
- RAG service over your own documents: ingestion, embeddings, search, a streaming FastAPI endpoint, structured logs and a 30-question eval set.
- A minimal tool-calling agent with two or three tools, tested against a fake client.
- Exit check: you can draw the request path and say what happens when each dependency fails.
Habits that compound
- Read the source. When a library confuses you, jump to its definition. Start with
__init__,__call__andforward. - Keep a surprises log. Each time a prediction is wrong, write down the rule that would have predicted it.
- Re-implement before you import. Write the 20-line version once, then use the library with understanding.