Skip to main content

Objects/moduleobject.c (part 3)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/moduleobject.c

This annotation covers module object creation and repr. See objects_module_detail (part 1) for module.__dict__, PyModule_New, and module.__getattr__.

Map

LinesSymbolRole
1-80PyModule_NewObjectCreate a module with a name
81-160module.__repr__<module 'name' from 'path'>
161-240module.__spec__Import spec attached after loading
241-320Multi-phase initPyModuleDef_Init for C extension modules
321-400module.__dir__List module attributes

Reading

PyModule_NewObject

// CPython: Objects/moduleobject.c:80 PyModule_NewObject
PyObject *
PyModule_NewObject(PyObject *name)
{
PyModuleObject *m = PyObject_GC_New(PyModuleObject, &PyModule_Type);
m->md_dict = PyDict_New();
m->md_state = NULL;
m->md_weaklist = NULL;
m->md_def = NULL;
/* Set __name__, __loader__, __package__, __spec__ to None */
PyDict_SetItemString(m->md_dict, "__name__", name);
PyDict_SetItemString(m->md_dict, "__loader__", Py_None);
PyDict_SetItemString(m->md_dict, "__package__", Py_None);
PyDict_SetItemString(m->md_dict, "__spec__", Py_None);
return (PyObject *)m;
}

All module attributes are stored in md_dict. __spec__ starts as None and is set by the import machinery after loading. md_state holds C extension module state (from multi-phase init); it is NULL for Python modules.

module.__repr__

// CPython: Objects/moduleobject.c:180 module_repr
static PyObject *
module_repr(PyModuleObject *m)
{
/* <module 'name' from 'file'> or <module 'name' (built-in)> */
PyObject *spec = PyDict_GetItemString(m->md_dict, "__spec__");
if (spec != NULL && spec != Py_None) {
return PyObject_CallMethod(spec, "__repr__", NULL);
}
PyObject *name = PyDict_GetItemString(m->md_dict, "__name__");
PyObject *file = PyDict_GetItemString(m->md_dict, "__file__");
if (file != NULL && file != Py_None) {
return PyUnicode_FromFormat("<module '%U' from '%U'>", name, file);
}
return PyUnicode_FromFormat("<module '%U'>", name);
}

repr(module) delegates to __spec__.__repr__() if a spec is present, giving <module 'foo' from '/path/to/foo.py'>. For built-ins and frozen modules, it falls back to <module 'sys' (built-in)>.

Multi-phase init

// CPython: Objects/moduleobject.c:280 PyModuleDef_Init
PyObject *
PyModuleDef_Init(struct PyModuleDef *def)
{
/* Register a module definition for multi-phase initialization.
Phase 1: PyInit_foo() returns the PyModuleDef (not a module object).
Phase 2: importlib calls Py_mod_exec slots on the module. */
if (PyType_Ready(&PyModuleDef_Type) < 0) return NULL;
Py_INCREF(def);
return (PyObject *)def;
}

Multi-phase init (PEP 451) allows a C extension's PyInit_foo to return a PyModuleDef instead of a module object. The import machinery calls Py_mod_create then Py_mod_exec slots. This enables sub-interpreter isolation and module state per-interpreter.

gopy notes

PyModule_NewObject is objects.NewModule in objects/module.go. Module attributes live in Module.Dict. module.__repr__ is objects.ModuleRepr. Multi-phase init is not yet supported; gopy C extensions use the single-phase path.