The goal is not to memorize the C API. It is to know what the details are: which rules exist, where they bite, and what a correct extension looks like — enough to specify the work precisely, review generated code against a real checklist, and debug it when it crashes. Lesson 08 is the boilerplate reference; Lesson 14 is the review checklist and the specification template.
Lessons are linear and each assumes only what came before. Every lesson ends with a quiz and hands-on exercises you can run from a plain Python REPL.
Lessons
-
01What a Python Object Actually Is
Every value is a heap struct beginning with a refcount and a type pointer. Boxing, runtime type dispatch, and the three layers of the C API.
-
02Reference Counting and Ownership
Strong, borrowed and stolen references; the manipulation macros; the borrowed-reference trap; and how to structure a function so it cannot leak.
-
03Type Objects and Slots
A class is a struct of function pointers. Mapping dunders to slots, the construction and destruction lifecycle, members versus getsets, static versus heap types.
-
04The Cycle Collector
Why refcounting leaks cycles, how CPython finds them, and the exact contract of
tp_traverse,tp_clearand the deallocation order. -
05The Error Model
The thread-local error indicator plus a sentinel return. Raising, propagating, catching, translating library errors, and not clobbering an exception during cleanup.
-
06Functions and Argument Parsing
Calling conventions from
METH_Oto vectorcall, the format-unit table and its lifetime hazards, building return values, and calling back into Python. -
07Frames, Code Objects and the Eval Loop
Where Python code runs, and the consequences of C functions having no frame: recursion guards, invisible tracebacks, signal handling, and reentrancy.
-
08Module Mechanics and Glue Code
The boilerplate lesson. Entry point, multi-phase initialization, module slots, per-module state instead of globals, and a complete annotated skeleton.
-
09Building and Packaging
pyproject.tomlandsetup.py, the build/test loop, reading ABI tags, the Limited API andabi3, platform notes, and what to do when the import fails. -
10The GIL and Thread State
What the lock protects, how to release it correctly around real work, entering Python from a foreign thread, and the two deadlocks extensions cause.
-
11Free-Threaded Python
What PEP 703 changed inside, the audit your extension needs, declaring support honestly, and choosing between critical sections,
PyMutexand thread-local state. -
12Buffers and Zero-Copy
Moving bulk data without copying or boxing, the request-flag contract, exporting your own buffer, and why a pinned buffer is what makes a detached compute loop sound.
-
13Wrapping a C Library
Handle types, deterministic release, use-after-close protection, error translation, callbacks from foreign threads, capsules, strings and paths.
-
14Alternatives, Checklist and Agent Brief
Cython, nanobind, cffi, PyO3 and when each wins; a complete review checklist organized by invariant; and a specification template for directing a coding agent.
Resources
-
Reference Material
A curated set of canonical documentation, PEPs and the few secondary sources worth the time, organized by lesson.
-
Glossary
Every term the course introduces, with a one-line definition and a link to the lesson that introduces it. Filterable.
Sample code
Four complete, compilable projects. All four build with MSVC on Windows and with GCC/Clang elsewhere, and their test suites pass on CPython 3.14. Each page below shows the full source syntax-highlighted and links to the original files.
-
hello
The smallest useful modern module: multi-phase init,
METH_OandMETH_FASTCALL, correct handling of an ambiguous error sentinel. Start here. -
counter
A heap type with per-module state and full cycle-GC support, validating getsets, and module state reached from both a method and a slot function.
-
bufsum
The buffer protocol and interpreter release: acquire, validate, detach, compute in plain C, re-attach, raise.
-
wraplib
A full wrapper around a fictional C library: opaque handle, idempotent
close(), context manager, error translation, callbacks, and a capsule.
cd code/hello
python -m pip install -e . --no-build-isolation -v
python -m pytest -q
Editing a .c file requires re-running the install command; an editable install links the compiled artifact, not the source.