Python from First PrinciplesPost 19 of 20 · 20 of 20 written

19. Roadmap and build-to-learn projects

Python · 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.

  1. 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.
  2. Functions, iteration and classes (Parts 5–8)
    • A small library with @retry and @timed decorators, plus tests.
    • A dataset class over a JSONL file with __len__, __getitem__ and __iter__, plus a batched() 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.
  3. 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 sync then uv run pytest with everything green.
  4. 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.
  5. 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 .grad and why zero_grad exists.
  6. 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__ and forward.
  • 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.