Skip to main content

Objects/typeobject.c

Source:

cpython 3.14 @ ab2d84fe1023/Objects/typeobject.c

Objects/typeobject.c is one of the largest files in CPython (~9800 lines). It implements the type metatype, PyType_Ready (slot inheritance), C3 MRO linearization, and the slot-wrapper machinery that exposes C-level slots as Python-visible methods.

Map

LinesSymbolRole
1-200Forward declarations, internal helpersSlot update machinery
201-700type_call, type_new, type_inittype.__call__, type.__new__
701-1200mro_implementation, mro_check_linearizationC3 MRO algorithm
1201-2000PyType_ReadyInitialize a type: fill slots, compute MRO, set up method wrappers
2001-3500Slot wrappersslot_tp_* functions that call Python-level dunder methods
3501-5000type_getattro, type_setattroAttribute access on type objects
5001-6500inherit_slots, fixup_slot_dispatchersSlot inheritance from base types
6501-9800tp_methods, tp_getset, type_memberstype's own methods and attributes

Reading

type.__call__ and object construction

// CPython: Objects/typeobject.c:1058 type_call
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
...
obj = type->tp_new(type, args, kwds);
if (obj == NULL) return NULL;
...
if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
Py_DECREF(obj);
return NULL;
}
}
return obj;
}

type.__call__ first calls tp_new to allocate, then tp_init to initialize. Subclasses that override __new__ and/or __init__ have their slots replaced by slot_tp_new/slot_tp_init, which dispatch to Python via _PyObject_Call.

C3 MRO linearization

mro_implementation implements the C3 linearization algorithm. It takes a type and its bases, runs C3 merge on their MRO lists, and returns the computed MRO as a tuple.

// CPython: Objects/typeobject.c:1780 mro_implementation
static PyObject *
mro_implementation(PyTypeObject *type)
{
...
// Build list of linearizations of bases + list of direct bases
// Run C3 merge
...
}

PyType_Ready

Initializes a statically defined type. This includes: setting ob_type if not set, computing the MRO, inheriting unset slots from the base type, filling in the tp_dict with methods and attributes, and calling PyType_Modified to invalidate caches.

// CPython: Objects/typeobject.c:7060 PyType_Ready
int
PyType_Ready(PyTypeObject *type)
{
...
if (type->tp_base == NULL && type != &PyBaseObject_Type) {
type->tp_base = &PyBaseObject_Type;
Py_INCREF(type->tp_base);
}
/* Initialize tp_bases */
bases = type->tp_bases;
if (bases == NULL) {
bases = PyTuple_Pack(1, type->tp_base);
...
type->tp_bases = bases;
}
/* Compute MRO */
mro = mro_implementation(type);
...
/* Inherit special slots */
inherit_slots(type, (PyTypeObject *)type->tp_base);
...
}

Slot wrappers

slot_tp_repr, slot_tp_hash, slot_tp_richcompare, etc. are generated wrappers. When a Python class defines __repr__, type_new (or fixup_slot_dispatchers) installs slot_tp_repr into tp_repr. This wrapper calls type_lookup(type, "__repr__") and then _PyObject_CallOneArg(func, self).

gopy notes

The gopy equivalent is split across objects/type.go, objects/type_call.go, and objects/usertype.go. PyType_Ready maps to objects.NewType; C3 MRO is in objects/type.go:mro; slot wrappers are implemented as Go closures stored in the Type struct's slot fields.