Python/import.c (part 8)
Source:
cpython 3.14 @ ab2d84fe1023/Python/import.c
This annotation covers the import machinery internals. See python_import7_detail for __import__, importlib, module spec resolution, and sys.modules caching.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1-80 | Import lock | Per-module lock to prevent import races |
| 81-160 | _PyImport_LoadDynamicModuleWithSpec | Load a .so / .pyd extension module |
| 161-260 | Frozen modules | Compile bytecode embedded in the interpreter |
| 261-380 | Namespace packages | __path__ without __init__.py |
| 381-500 | PyImport_ImportModuleLevelObject | Level-relative import resolution |
Reading
Import lock
// CPython: Python/import.c:220 _PyImport_AcquireLock
void
_PyImport_AcquireLock(PyInterpreterState *interp)
{
/* Per-module locking: two threads importing the same module
get serialized; different modules import concurrently. */
struct _import_lock *lock = &interp->imports.lock;
PyThread_acquire_lock(lock->mutex, WAIT_LOCK);
while (lock->locked && lock->thread != PyThread_get_thread_ident()) {
lock->waiters++;
PyThread_release_lock(lock->mutex);
PyThread_acquire_lock(lock->mutex, WAIT_LOCK);
lock->waiters--;
}
lock->locked = 1;
lock->thread = PyThread_get_thread_ident();
lock->level++;
PyThread_release_lock(lock->mutex);
}
The import lock is reentrant (same thread can acquire multiple times). Without it, two threads importing a module that has side effects could execute the module body concurrently.
Frozen modules
// CPython: Python/import.c:480 import_find_frozen
static PyObject *
import_find_frozen(PyThreadState *tstate, PyObject *name)
{
/* Search the table of frozen modules (compiled into the interpreter) */
struct _frozen *p;
for (p = PyImport_FrozenModules; p->name != NULL; p++) {
if (strcmp(p->name, PyUnicode_AsUTF8(name)) == 0) {
return unmarshal_frozen_module(tstate, p);
}
}
return Py_NewRef(Py_None); /* not found */
}
Frozen modules are bytecode bytes embedded in Python/frozen.c (generated by Tools/scripts/freeze.py). They bootstrap the import system before the filesystem is available. _frozen_importlib and _frozen_importlib_external are always frozen.
Namespace packages
// CPython: Python/import.c:640 _find_spec_legacy
static PyObject *
_find_spec_legacy(PyObject *finder, PyObject *name, PyObject *path)
{
/* Finder returned a loader; if None, it's a namespace package portion */
...
if (loader == Py_None) {
/* Namespace package: accumulate path portions */
portions = PyObject_GetAttr(loader, str_submodule_search_locations);
...
}
}
Namespace packages (PEP 420) have no __init__.py. Their __path__ is a _NamespacePath that searches multiple directories. Multiple installed packages can contribute to the same namespace package.
gopy notes
The import lock is vm.ImportLock in vm/eval_import.go, implemented with a sync.Mutex and a reentrancy counter per goroutine (using goroutine_id). Frozen modules are registered in stdlibinit/registry.go via registerFrozen. Namespace package path joining is module/importlib.NamespacePath.