Skip to main content

Objects/moduleobject.c (part 5)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/moduleobject.c

This annotation covers module initialization and attribute access. See objects_moduleobject4_detail for PyModule_New, PyModule_AddObject, and multi-phase extension module init.

Map

LinesSymbolRole
1-80module.__init_subclass__Hook for module subclasses
81-160module.__repr__<module 'name' from 'path'>
161-240module.__getattr__Lazy attribute loading via __getattr__
241-360module.__spec__ModuleSpec object attached at import
361-500module.__dir__Return list(__dict__.keys())

Reading

module.__repr__

// CPython: Objects/moduleobject.c:180 module_repr
static PyObject *
module_repr(PyObject *self)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
PyObject *spec = PyObject_GetAttrString(self, "__spec__");
if (spec != NULL) {
PyObject *repr = PyObject_CallMethod(spec, "_repr_", "O", self);
if (repr != NULL) return repr;
PyErr_Clear();
}
PyObject *name = PyObject_GetAttrString(self, "__name__");
PyObject *filename = PyObject_GetAttrString(self, "__file__");
if (filename != NULL)
return PyUnicode_FromFormat("<module %R from %R>", name, filename);
return PyUnicode_FromFormat("<module %R (built-in)>", name);
}

repr(os) produces <module 'os' from '/usr/lib/python3.14/os.py'>. The repr delegates to __spec__._repr_() if available, so the import system can customize it.

module.__getattr__

// CPython: Objects/moduleobject.c:240 module_getattro
static PyObject *
module_getattro(PyObject *m, PyObject *name)
{
PyObject *attr = _PyObject_GenericGetAttrWithDict(m, name, NULL, 0);
if (attr != NULL) return attr;
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL;
/* Check for __getattr__ in the module dict */
PyObject *getattr = PyObject_GetAttrString(m, "__getattr__");
if (getattr != NULL) {
attr = PyObject_CallOneArg(getattr, name);
Py_DECREF(getattr);
return attr;
}
...
}

If a module defines __getattr__, it is called when a normal attribute lookup fails. This enables lazy imports: math.__getattr__ could import math.tau on demand from a sub-module.

module.__spec__

# CPython: Objects/moduleobject.c:60 module dict keys set by import system
# __name__ — dotted module name (e.g., 'os.path')
# __spec__ — ModuleSpec: contains name, loader, origin, submodule_search_locations
# __loader__ — the loader that created this module
# __package__ — parent package name, or '' for top-level
# __file__ — filesystem path to the source or .pyc
# __cached__ — path to .pyc cache file

__spec__ is a ModuleSpec populated by the import machinery (importlib._bootstrap). It carries all the metadata needed to reload the module. importlib.reload(m) uses m.__spec__ to re-run the loader.

module.__dir__

// CPython: Objects/moduleobject.c:320 module_dir
static PyObject *
module_dir(PyObject *self, PyObject *args)
{
PyObject *result = NULL;
PyObject *dict = PyObject_GetAttrString(self, "__dict__");
if (dict != NULL) {
if (PyDict_Check(dict))
result = PyDict_Keys(dict);
Py_DECREF(dict);
}
return result;
}

dir(os) returns the list of keys in the module's __dict__. If the module defines __dir__, that is called instead (via module_getattro's fallback).

gopy notes

module.__repr__ is objects.Module.Repr in objects/module.go. It reads objects.Module.Name and objects.Module.File. module.__getattr__ calls objects.Module.Dict.Get(name) then falls back to the __getattr__ attribute if present. module.__dir__ returns objects.DictKeys(module.Dict).