Skip to main content

Objects/typeobject.c (part 12)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/typeobject.c

This annotation covers isinstance/issubclass and MRO computation. See objects_typeobject11_detail for type.__new__, type.__init__, and slot inheritance.

Map

LinesSymbolRole
1-80type.__instancecheck__isinstance(obj, cls)
81-160type.__subclasscheck__issubclass(sub, cls)
161-280mro_internalCompute the MRO for a new type
281-420C3 linearizationThe merge algorithm
421-600_PyType_LookupAttribute lookup following the MRO

Reading

type.__instancecheck__

// CPython: Objects/typeobject.c:4880 type_instancecheck
static PyObject *
type_instancecheck(PyObject *cls, PyObject *instance)
{
int r = PyObject_IsInstance(instance, cls);
if (r < 0) return NULL;
return PyBool_FromLong(r);
}

// CPython: Objects/typeobject.c:3120 PyObject_IsInstance
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
/* Check __class__ attribute first for virtual subclasses */
PyObject *icls = PyObject_GetAttr(inst, &_Py_ID(__class__));
if (PyType_Check(cls)) {
/* Fast path: check ob_type */
int result = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
if (!result && icls != NULL)
result = PyType_IsSubtype((PyTypeObject *)icls, (PyTypeObject *)cls);
...
}
}

isinstance checks the actual type first, then __class__ (which may differ for proxy objects). ABCs (abstract base classes) can override __instancecheck__ to implement virtual subclassing.

C3 linearization

// CPython: Objects/typeobject.c:2480 mro_internal
static PyObject *
mro_internal(PyTypeObject *type, PyObject **p_old_mro)
{
/* C3 linearization:
L[C(B1, B2, ...)] = C + merge(L[B1], L[B2], ..., [B1, B2, ...])
merge: take the head of the first list if it doesn't appear in the
tail of any other list. Remove it from all lists. Repeat.
*/
...
}

C3 ensures that the MRO is consistent with both the local precedence order (subclass before base) and the monotonicity constraint (the MRO of a base is preserved in the subclass's MRO). A TypeError is raised when no consistent linearization exists.

_PyType_Lookup

// CPython: Objects/typeobject.c:3640 _PyType_Lookup
PyObject *
_PyType_Lookup(PyTypeObject *type, PyObject *name)
{
/* Search the MRO for `name` */
PyObject *mro = type->tp_mro;
Py_ssize_t n = PyTuple_GET_SIZE(mro);
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *base = PyTuple_GET_ITEM(mro, i);
PyObject *dict = ((PyTypeObject *)base)->tp_dict;
PyObject *res = PyDict_GetItemWithError(dict, name);
if (res != NULL) return res;
}
return NULL;
}

_PyType_Lookup walks the MRO and searches each class's __dict__. It does NOT call __getattribute__; it is the raw slot lookup used by the attribute machinery.

gopy notes

type.__instancecheck__ is objects.TypeInstanceCheck in objects/type.go. MRO computation is objects.ComputeMRO using the C3 algorithm. _PyType_Lookup is objects.TypeLookup, which walks type.MRO and calls objects.DictGetItem on each class's dict.