python 的 object 与type的关系 是并列关系,两种是相互依赖的
查询父类
type.__bases__
object.__bases__
(<class ‘object’>,)
()
查询类型
type(type)
type(object)
<class ‘type’>
<class ‘type’>
在python中,type用于描述类型信息,object用于描述继承关系
object是所有类的父类,包括type
object是type的实例,所有类型都是type的实例
type 站在 类型实例关系金字塔 的顶端
object 站在继承金字塔的顶端
python这样做,才会有那句 一切都是对象,可以动态得修改 类型 和 类
在python层面是无法理解这样是怎么做到的,需要在c的层面
类型对象的类型:PyType_Type
我们知道了 type 在底层对应 PyType_Type,而它在 “Object/typeobject.c” 中定义,因为我们说所有的类型对象加上元类都是要预先定义好的,所以在源码中就必须要以静态全局变量的形式出现。
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 */
// ...
(reprfunc)type_repr, /* tp_repr */
// ...
};
所有的类型对象加上元类都是 PyTypeObject 这个结构体实例化得到的,所以它们内部的成员都是一样的,只不过传入的值不同,实例化之后的结果也不同,可以是 PyLong_Type、可以是 PyFloat_Type,也可以是这里的 PyType_Type。
里面的宏 PyVarObject_HEAD_INIT,我们看到它传递的是一个 &PyType_Type,说明它把自身的类型也设置成了 PyType_Type。换句话说,PyType_Type 里面的 ob_type 成员指向的还是 PyType_Type。
所以所有类型的类型都是type
类型对象的基类:PyBaseObject_Type
类型对象内部的 tp_base 表示继承的基类,那么对于PyType_Type来讲,它内部的 tp_base 肯定是PyBaseObject_Type(object)。但它的 tp_base 居然是个 0,如果为 0 的话则表示没有这个属性。
为 0 的原因就在于我们目前看到的类型对象是一个半成品,因为 Python 的动态性,显然不可能在定义的时候就将所有成员属性都设置好、然后解释器一启动就会得到我们平时使用的类型对象。
目前看到的类型对象是一个半成品,有一部分成员属性是在解释器启动之后再进行动态完善的。
PyBaseObject_Type 位于 Object/object.c 中,
PyTypeObject PyBaseObject_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"object", /* tp_name */
sizeof(PyObject), /* tp_basicsize */
0, /* tp_itemsize */
object_dealloc, /* tp_dealloc */
// ...
object_repr, /* tp_repr */
// ...
};
我们看到PyBaseObject_Type的类型也被设置成了PyType_Type
而PyType_Type类型对象在被完善之后,它的 tp_base 也会指向PyBaseObject_Type。所以之前我们说 Python 中的 type 和 object 是同时出现的,它们的定义是需要依赖彼此的。
参考资料
《源码探秘 CPython》3. type 和 object 的恩怨纠葛
Python 的 type 和 object 之间是怎么一种关系?