CPython is the reference implementation of the Python programming language, written in C. This document provides an architectural overview of CPython's core systems, covering:
For specific subsystems, see:
Sources: Python/bytecodes.c1-100 Python/ceval.c1-50 Python/optimizer.c1-50 Objects/typeobject.c1-50
Diagram: CPython Architecture and Data Flow
This diagram shows how Python code flows through the system, from source to execution, and the key C structures and files involved.
Sources: Python/bytecodes.c1-10 Python/ceval.c1-30 Python/optimizer.c115-150 Python/compile.c Objects/typeobject.c1-40 Python/pystate.c1-50
The heart of CPython's execution model is Python/bytecodes.c which serves as the single source of truth for all bytecode instructions. This file uses a domain-specific language with macros like inst(), op(), and macro() to define instructions.
Diagram: Bytecode Definition and Code Generation Pipeline
The Python/bytecodes.c1-147 file contains instruction definitions using special macros:
inst(name, ...): Defines a tier 1 instructionop(name, ...): Defines a micro-operation (UOp)macro(name): Defines a macro instruction composed of multiple opsfamily(name, ...): Defines a specialization familyCode generators in Tools/cases_generator/ process this file to produce execution handlers, metadata, and optimization rules.
Sources: Python/bytecodes.c1-147 Python/generated_cases.c.h1-20 Python/executor_cases.c.h1-20 Python/optimizer_cases.c.h1-20
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 is executed frequently (default threshold: 128 times), CPython may optimize it into a Tier 2 executor.
Diagram: Tier 2 Optimization Pipeline
The optimizer performs several key analyses:
Key structures:
_PyExecutorObject: Represents a compiled trace Include/internal/pycore_optimizer.h_PyUOpInstruction: Micro-operation with opcode, oparg, and operands Include/internal/pycore_uop.hJitOptContext: Optimization context with symbol tables Python/optimizer_analysis.cSources: Python/optimizer.c115-200 Python/optimizer_analysis.c1-100 Python/optimizer_bytecodes.c1-100 Include/internal/pycore_optimizer.h1-50
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 can be configured through several mechanisms:
| Option | Effect | Files |
|---|---|---|
--enable-optimizations | Profile-guided optimization | configure.ac |
--enable-experimental-jit | Enable JIT compiler | configure.ac Python/jit.c |
--disable-gil | Free-threading mode | configure.ac affects all runtime code |
Py_DEBUG | Debug builds with assertions | pyconfig.h |
Py_REF_DEBUG | Reference count debugging | Include/object.h |
PyConfig: Main configuration structure Include/cpython/initconfig.hPYTHONPATH, PYTHONHOME, PYTHONOPTIMIZE, etc.-X options: -X dev, -X utf8, -X tracemalloc, etc.sys.flags: Access configuration from PythonConfiguration processing: Python/initconfig.c
| Level | Effect | Bytecode Changes |
|---|---|---|
-O | Basic optimization | Remove assert statements, __debug__ = False |
-OO | Remove docstrings | Also remove __doc__ attributes |
Sources: Python/initconfig.c1-100 configure.ac Include/cpython/initconfig.h
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 5 days to refresh again.