Skip to main content

Objects/typeobject.c (part 2)

cpython 3.14 @ ab2d84fe1023/Objects/typeobject.c

This annotation covers class creation mechanics in Objects/typeobject.c. For the slot lookup protocol, type.__call__, and the descriptor protocol see the python_typeobject_c annotation.

Map

LinesSymbolRole
1-600mro_implementation, calculate_metaclassC3 MRO computation
601-1200type_new_impltype.__new__ for user-defined classes
1201-1600__init_subclass__ dispatchCalled after each subclass is created
1601-1900__set_name__ protocolCalled on descriptors after class creation
1901-2600update_one_slotPropagate inherited C slots to subclass
2601-9000Misc type methodstype_repr, type_getattro, type_setattro, etc.

Reading

C3 MRO linearisation

mro_implementation implements the C3 algorithm. It builds a merge list of the MROs of all bases plus the bases list itself, then repeatedly takes the head of the first list that does not appear in the tail of any other list.

// CPython: Objects/typeobject.c:2180 mro_implementation
static PyObject *
mro_implementation(PyTypeObject *type)
{
/* Merge = [mro(B) for B in bases] + [bases] */
...
while (1) {
/* find good head */
good = NULL;
for (i = 0; i < to_merge_size; i++) {
PyObject *candidate = PyList_GET_ITEM(...);
if (!tail_contains(to_merge, i, candidate))
good = candidate;
}
if (good == NULL) break;
...
}
}

type_new_impl class creation

type.__new__(mcs, name, bases, namespace) validates the bases, computes the MRO, copies slots and descriptors, then calls __init_subclass__ on each base and __set_name__ on each descriptor in the new class's namespace.

update_one_slot

When a method is overridden in a subclass, update_one_slot propagates the C-level slot pointer (tp_richcompare, nb_add, etc.) from the defining class through all subclasses. This ensures that C code can call through the C slot pointer without checking the Python method resolution order on every call.

__set_name__ protocol

After class creation, type_new_impl iterates all values in the namespace. For each value that has a __set_name__ method, it calls value.__set_name__(owner, name). This allows descriptors to know the attribute name they were assigned to.

gopy notes

objects/type.go implements type.__new__. MRO computation is in objects/type.go:computeMRO. __init_subclass__ is called from objects/usertype.go. update_one_slot is not needed in gopy since slot dispatch goes through the Python MRO rather than C slot pointers.