A course

CPython Runtime Internals for C Extension Authors

The invariants the interpreter expects you to maintain — objects, reference counting, types, the cycle collector, errors, frames, the GIL, free-threading, buffers — plus the boilerplate and the build. Targets CPython 3.13 and 3.14, including free-threaded builds.

What this is for

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

  1. 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.

  2. 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.

  3. 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.

  4. 04The Cycle Collector

    Why refcounting leaks cycles, how CPython finds them, and the exact contract of tp_traverse, tp_clear and the deallocation order.

  5. 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.

  6. 06Functions and Argument Parsing

    Calling conventions from METH_O to vectorcall, the format-unit table and its lifetime hazards, building return values, and calling back into Python.

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

  8. 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.

  9. 09Building and Packaging

    pyproject.toml and setup.py, the build/test loop, reading ABI tags, the Limited API and abi3, platform notes, and what to do when the import fails.

  10. 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.

  11. 11Free-Threaded Python

    What PEP 703 changed inside, the audit your extension needs, declaring support honestly, and choosing between critical sections, PyMutex and thread-local state.

  12. 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.

  13. 13Wrapping a C Library

    Handle types, deterministic release, use-after-close protection, error translation, callbacks from foreign threads, capsules, strings and paths.

  14. 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

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.

Running the samples
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.