From a language semantics perspective, both type
and object
exist, fully initialized, from the moment the program begins. Whatever the implementation does to get things into that state doesn't have to follow the rules of what the implementation allows you to do.
From a CPython implementation perspective, both type
and object
are statically allocated at C level, and neither is created first. You can see the variable definitions in Objects/typeobject.c
. Here's object
:
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
sizeof(PyObject), /* tp_basicsize */
0, /* tp_itemsize */
object_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
object_repr, /* tp_repr */
...
};
and here's type
:
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)type_repr, /* tp_repr */
...
};
When interpreter initialization begins, both type
and object
are in a half-initialized state, and the PyType_Ready
function is responsible for finishing their initialization. The type pointers are set up in the variable definitions, but setting the superclass pointers is part of PyType_Ready
's job, and plenty of other initialization needs to be handled by PyType_Ready
- for example, the types don't have a __dict__
yet.
Incidentally, using some weird metaclasses and the fact that Python allows you to reassign __class__
on instances of user-defined classes, we can set up our own classes A
and B
where B
is a subclass of A
and both A
and B
are instances of B
, much like the situation with object
and type
. This is nothing like how object
and type
are actually created, though:
class DummyMeta(type):
pass
class A(type, metaclass=DummyMeta):
pass
class B(A):
pass
B.__class__ = B
A.__class__ = B
print(isinstance(A, B))
print(isinstance(B, B))
print(issubclass(B, A))
Output:
True
True
True