Skip to main content

Python/pylifecycle.c

cpython 3.14 @ ab2d84fe1023/Python/pylifecycle.c

Python/pylifecycle.c implements CPython's startup and shutdown sequence. Py_InitializeFromConfig is the main entry point; it runs in multiple phases to allow configuration, pre-initialization (signal handling, locale), core initialization (type system, built-ins), and full initialization (stdlib, site). Py_FinalizeEx runs the reverse: calling finalizers, clearing modules, running GC, and freeing interpreter state.

Map

LinesSymbolRole
1-100includes, forward declsPhase flags, pre-init state
101-400pyinit_preinitSignal setup, locale config, pre-config validation
401-800pyinit_coreType system, built-ins, import system bootstrap
801-1200pyinit_mainSite module, readline, __main__, faulthandler
1201-1600Py_InitializeFromConfigOrchestrates all three phases
1601-2000Py_FinalizeExModule teardown, GC finalization, memory release
2001-2500Py_NewInterpreter, Py_EndInterpreterSub-interpreter lifecycle
2501-3000misc helpersPy_AtExit, Py_ExitStatusException, _Py_ClearStandardStreamEncoding

Reading

Multi-phase initialization

Startup is split into three phases to allow embedding code to configure Python between phases. pyinit_preinit runs with minimal state; pyinit_core bootstraps the type and import systems; pyinit_main imports the site module and sets up __main__.

// CPython: Python/pylifecycle.c:1250 Py_InitializeFromConfig
PyStatus
Py_InitializeFromConfig(const PyConfig *config)
{
...
status = pyinit_preinit(runtime, &config);
if (_PyStatus_EXCEPTION(status)) goto done;
status = pyinit_core(runtime, &config, &tstate);
if (_PyStatus_EXCEPTION(status)) goto done;
status = pyinit_main(tstate);
...

Py_FinalizeEx: shutdown order

Py_FinalizeEx must tear down in a specific order to avoid dangling references. _Py_FinalizeInterpreter calls module __del__, clears sys.modules, runs GC, clears thread states, then frees the interpreter structure.

// CPython: Python/pylifecycle.c:1680 Py_FinalizeEx
int
Py_FinalizeEx(void)
{
...
_Py_FinalizeInterpreter(tstate);
/* After this point, no Python code can run */
_PyRuntime_Finalize(&_PyRuntime);
return 0;
}

Sub-interpreter creation

Py_NewInterpreter creates an isolated interpreter state sharing the same process but with its own sys.modules, builtins, and GIL (or no GIL in the free-threaded build).

// CPython: Python/pylifecycle.c:2050 Py_NewInterpreterFromConfig
PyStatus
Py_NewInterpreterFromConfig(PyThreadState **tstate_p,
const PyInterpreterConfig *config)
{
PyInterpreterState *interp = PyInterpreterState_New();
...
status = pycore_init_types(interp);
...
status = init_interp_main(tstate);

gopy notes

pythonrun/runstring.go in gopy is the partial equivalent of pyinit_main. Full lifecycle management (multiple phases, sub-interpreters) is not yet implemented. The pyinit_core sequence is the model for any future gopy.Initialize() function.

CPython 3.14 changes

3.14 added Py_NewInterpreterFromConfig as the public API for sub-interpreter creation with an explicit PyInterpreterConfig. pyinit_core gained hooks for the new annotationlib lazy annotation evaluation module. Py_FinalizeEx now drains the _Py_FinalizeDeferred list before clearing thread states.