CPython is the reference implementation of the Python programming language, written in C. This document provides an architectural overview of CPython's core systems for Python 3.14 (released October 2025) and 3.15 (in development).
Major architectural components:
Navigation to detailed subsystems:
Sources: Doc/whatsnew/3.14.rst1-100 Python/bytecodes.c1-150 Python/ceval.c Python/optimizer.c1-100 Objects/typeobject.c1-100
Diagram: CPython Architecture - Data Flow and Key Code Symbols
This diagram maps the flow of Python code through CPython's major subsystems, annotated with actual function names, file paths, and data structures from the codebase. Each box represents concrete code entities that can be located in the source tree.
Sources: Python/bytecodes.c1-147 Python/ceval.c Python/compile.c Python/optimizer.c1-200 Python/generated_cases.c.h1-100 Python/executor_cases.c.h1-100 Python/optimizer_cases.c.h1-100 Objects/typeobject.c1-100 Python/pystate.c1-150 Include/object.h Python/jit.c
Python/bytecodes.c is the single source of truth for all bytecode instructions in CPython. It uses a domain-specific language (DSL) with macros to define instructions, which are then processed by code generators to produce multiple output files.
Diagram: Bytecode DSL to Generated Code Pipeline
Instruction Definition Macros:
| Macro | Purpose | Example |
|---|---|---|
inst(name, stack_effect) | Tier 1 bytecode instruction | inst(LOAD_FAST, (-- value)) |
op(name, stack_effect) | Micro-operation (UOp) for Tier 2 | op(_GUARD_TOS_INT, (value -- value)) |
macro(name) | Combines multiple ops | macro(STORE_FAST) = _SWAP_FAST + POP_TOP; |
family(name, ...) | Specialization family | family(TO_BOOL, ...) = { TO_BOOL_BOOL, ... }; |
replicate(N) | Generate N copies with suffixes | replicate(8) inst(LOAD_FAST, ...) |
Code Generation Process:
Sources: Python/bytecodes.c1-147 Python/generated_cases.c.h1-100 Python/executor_cases.c.h1-100 Python/optimizer_cases.c.h1-100 Include/internal/pycore_opcode_metadata.h1-50 Include/internal/pycore_uop_ids.h1-50 Include/internal/pycore_uop_metadata.h1-50
CPython uses a three-tier execution model to balance performance and compatibility:
| Tier | Description | Implementation | When Used |
|---|---|---|---|
| Tier 1 | Traditional bytecode interpreter | Python/generated_cases.c.h included in Python/ceval.c | All code initially, cold code |
| Tier 2 | Optimized UOp traces | Python/executor_cases.c.h with Python/optimizer.c | Hot loops after ~128 iterations |
| JIT | Native machine code | Python/jit.c with Tools/jit/ stencils | Tier 2 traces when JIT enabled |
The core evaluation loop is _PyEval_EvalFrameDefault() in Python/ceval.c1-30 It executes bytecode instructions generated from Python/bytecodes.c using a switch-based dispatch mechanism.
Diagram: Tier 1 Bytecode Interpreter Execution Flow
Key data structures:
_PyInterpreterFrame: Current frame being executed Include/internal/pycore_interpframe.hPyCodeObject: Contains bytecode and metadata Include/cpython/code.h_PyStackRef: Stack reference wrapper for values Include/internal/pycore_stackref.hSources: Python/ceval.c1-30 Python/generated_cases.c.h1-100 Python/specialize.c Include/internal/pycore_interpframe.h
When a JUMP_BACKWARD instruction executes frequently (default: JUMP_BACKWARD_INITIAL_VALUE = 128), the optimizer converts the hot loop into a Tier 2 trace of micro-operations (UOps).
Diagram: Tier 2 Optimizer - Function Names and Data Structures
Optimization Techniques:
| Technique | Implementation | File |
|---|---|---|
| Symbolic execution | op(_LOAD_FAST), op(_GUARD_TOS_INT) in DSL | Python/optimizer_bytecodes.c90-600 |
| Type tracking | JitOptSymbol with type, const, null info | Python/optimizer_analysis.c |
| Guard elimination | optimize_to_bool, eliminate_pop_guard | Python/optimizer_analysis.c |
| Constant folding | Evaluate ops on sym_is_const values | Python/optimizer_bytecodes.c |
| Copy propagation | Track value flow in frame->locals | Python/optimizer_analysis.c |
Key Data Structures:
Sources: Python/optimizer.c80-600 Python/optimizer_analysis.c1-800 Python/optimizer_bytecodes.c1-700 Include/internal/pycore_optimizer.h1-150 Include/internal/pycore_backoff.h
When JIT is enabled (via --enable-experimental-jit build flag), Tier 2 traces are compiled to native machine code.
Diagram: JIT Compilation Process
The JIT uses a copy-and-patch approach:
JIT structures:
_Py_CODEUNIT *jit_code: Pointer to native code in _PyExecutorObjectSources: Python/jit.c1-100 Tools/jit/_targets.py1-50 Tools/jit/_stencils.py
All Python objects derive from PyObject, defined in Include/object.h The type system is built on PyTypeObject defined in Objects/typeobject.c
Diagram: Object Type Hierarchy
Every Python object starts with the PyObject header:
Include/object.h defines this base structure along with reference counting macros:
Py_INCREF(op): Increment reference countPy_DECREF(op): Decrement and potentially deallocatePy_XINCREF(op), Py_XDECREF(op): NULL-safe versionsSources: Include/object.h Objects/object.c1-100 Objects/typeobject.c1-100
CPython uses a multi-layered memory management system:
Diagram: Memory Management Layers
The primary memory management mechanism is reference counting:
ob_refcnt tracking how many references existtp_dealloc is calledObjects/object.c1-100 implements core reference counting functions.
The cyclic garbage collector handles reference cycles:
PyGC_HeadImplementations:
In free-threaded builds (Py_GIL_DISABLED):
Sources: Objects/object.c1-200 Python/gc.c1-50 Python/gc_free_threading.c1-50 Include/internal/pycore_object.h1-100
CPython's runtime state is organized hierarchically:
Diagram: Runtime State Hierarchy
| Structure | Scope | Key Fields | File |
|---|---|---|---|
_PyRuntimeState | Process-wide | interpreters, gilstate, gc | Include/internal/pycore_runtime.h |
PyInterpreterState | Per-interpreter | modules, builtins, ceval, gc | Include/internal/pycore_interp.h |
PyThreadState | Per-thread | interp, frame, recursion_limit, curexc_* | Include/cpython/pystate.h |
_PyInterpreterFrame | Per-call | f_code, f_locals, prev, stacktop | Include/internal/pycore_interpframe.h |
Current thread state is accessed via thread-local storage:
_Py_tss_tstate: TLS variable in Python/pystate.c73_PyThreadState_GET(): Fast macro to get current thread statePyGILState_Ensure(): Acquire GIL and get thread stateThe GIL (Global Interpreter Lock) is managed through:
_PyEval_AcquireLock(): Acquire GIL_PyEval_ReleaseLock(): Release GILdrop_gil(), take_gil(): Core GIL operationsSources: Python/pystate.c1-150 Include/internal/pycore_runtime.h Include/internal/pycore_interp.h Python/ceval.c
CPython's initialization follows a carefully orchestrated sequence:
Diagram: Initialization and Shutdown Sequence
Key initialization functions:
Py_InitializeFromConfig(): Main entry point Python/pylifecycle.c_PyRuntime_Initialize(): Initialize global runtime state Python/pystate.cpycore_init_types(): Initialize built-in types Python/pylifecycle.c_PyImport_Init(): Initialize import machinery Python/import.cSources: Modules/main.c Python/initconfig.c1-50 Python/pylifecycle.c1-100 Python/pystate.c1-100
CPython employs several optimization strategies:
Bytecode instructions can be specialized based on observed types at runtime:
_Py_Specialize_*() functions replace generic opcodes with specialized versionsLOAD_ATTR → LOAD_ATTR_INSTANCE_VALUE, BINARY_OP → BINARY_OP_ADD_INTImplementation: Python/specialize.c
Specialized instructions use inline cache entries to store:
Cache entries follow the instruction in bytecode: opcode.h cache definitions
The optimizer applies several transformations:
Implementation: Python/optimizer_analysis.c Python/optimizer_bytecodes.c
Frequently allocated types maintain freelists to avoid malloc/free overhead:
Implementation: Include/internal/pycore_freelist.h Objects/object.c
Sources: Python/specialize.c1-50 Python/optimizer_analysis.c1-100 Include/internal/pycore_freelist.h
CPython behavior is configured through build-time options, runtime configuration, and command-line flags.
| Configure Option | Effect | Implementation Files |
|---|---|---|
--enable-optimizations | Profile-guided optimization (PGO) | configure.ac3847-3900 Makefile.pre.in |
--enable-experimental-jit | JIT compiler with copy-and-patch | configure.ac Python/jit.c Tools/jit/ |
--disable-gil | Free-threaded mode (Py_GIL_DISABLED) | configure.ac impacts all C code |
--with-tail-call-interp | Tail-call interpreter (Clang 19+) | configure.ac Python/ceval.c |
--with-pydebug | Debug build with Py_DEBUG | configure.ac enables assertions |
--with-trace-refs | Track all object allocations | configure.ac Include/object.h |
--with-valgrind | Valgrind compatibility | configure.ac |
Include/cpython/initconfig.h defines PyConfig with fields for:
optimization_level: 0, 1 (-O), or 2 (-OO)bytes_warning: Warn on bytes/str comparisonsinspect: Enter interactive mode after scriptisolated: Isolated mode (ignore environment variables)use_environment: Use PYTHON* environment variablesdev_mode: Development mode (-X dev)Configuration flow: PyConfig_Read() → Py_InitializeFromConfig() in Python/initconfig.c
| Option | Effect | PyConfig Field |
|---|---|---|
-O | __debug__ = False, remove asserts | optimization_level = 1 |
-OO | Also remove docstrings | optimization_level = 2 |
-X dev | Development mode, extra warnings | dev_mode = 1 |
-X gil=0 | Disable GIL (free-threaded builds only) | Runtime check |
-X importtime | Show import time breakdown | Flag check in import code |
-X int_max_str_digits=N | Limit int string conversion | int_max_str_digits |
Environment Variables:
PYTHONPATH: Prepend to sys.pathPYTHONHOME: Override standard library locationPYTHONOPTIMIZE: Same as -OPYTHONDONTWRITEBYTECODE: Don't write .pyc filesPYTHON_GIL=0: Disable GIL at runtime (Python 3.13+)PYTHON_UOPS_OPTIMIZE=0: Disable Tier 2 optimizerSources: Python/initconfig.c1-200 configure.ac1-100 Include/cpython/initconfig.h Doc/using/configure.rst1-100
CPython includes extensive testing infrastructure:
| Tool | Purpose | Usage |
|---|---|---|
sys._debugmallocstats() | Memory allocation stats | Call from Python |
_opcode.get_executor() | Inspect Tier 2 executors | Lib/test/test_capi/test_opt.py33-42 |
PYTHONUOPS_OPTIMIZE=0 | Disable Tier 2 optimizer | Environment variable |
-X dev | Development mode with warnings | Command-line flag |
Tier 2 compilation can be traced with:
PYTHON_OPT_DEBUG=1: Print optimization decisions_opcode moduleSources: Lib/test/test_capi/test_opt.py1-200 Lib/test/test_gc.py1-100 Python/optimizer.c
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.