Python源码学习之PyType_Type和PyBaseObject_Type详解
PyType_Type和PyBaseObject_Type
PyObject和PyTypeObject内容的最后指出下图中对实例对象和类型对象的理解是不完全正确的,
浮点类型对象全局唯一,Python在C语言层面实现过程中将其定义为一个全局静态变量,定义于Object/floatobject.c
中,命名为PyFloat_Type
。
PyTypeObject PyFloat_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "float", sizeof(PyFloatObject), 0, (destructor)float_dealloc, /* tp_dealloc */ // ... (reprfunc)float_repr, /* tp_repr */ // ... };
- 第2行使用初始化
ob_refcnt
、ob_type
以及ob_size
三个字段,PyVarObject_HEAD_INIT
的定义可以参考博文1.4.3节的内容。 - 第3行将
tp_name
字段初始化成类型名称"float" - 再往下是各种操作的函数指针
ob_type
指针指向PyType_Type
,这也是一个静态定义的全局变量。代表“类型的类型” 的type对象就是PyType_Type
。
一. 类型的类型—PyType_Tpye(type的实体)
上文中,float类型对象在底层实现过程中对应PyFloat_Type
全局静态变量。Python类型是一种对象,也有自己的类型,即Python中的type。
>>> float.__class__ <class 'type'>
自定义类型也遵循同样的规则,
>>> class Foo(object): ... pass ... >>> Foo.__class__ <class 'type'>
在查看PyFloat_Type
代码实现时,ob_type
字段指向的PyType_Type
就是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
对象都是通过PyType_Type
创建。PyType_Type
是PyTypeObject
的一个实例。 PyType_Type
是类型机制中至关重要的对象,是所有类型的类型,称为元类型。- 第2行代码处
PyType_Type
将自身的ob_type
字段指向它自己。
>>> type.__class__ <class 'type'> >>> type.__class__ is type True
由此,以float为例,可以绘制一个更完善但是并不完全正确的实例对象和类型对象在内存中的关系图,
二. 类型之基—PyBaseObject_Type(object的实体)
上一节中红色标记的语句,并不完全正确是因为思考过程中忽略了object
对象的存在。
object
是另一个特殊的类型,是所有类型的基类。同样可以通过PyFloat_Type
中tp_base
字段顺藤摸瓜找到。然而,在源码的第2行的PyVarObject_HEAD_INIT定义中,该字段并没有初始化,
0, /* tp_base */
更进一步查找代码中PyFloat_Type
出现的地方,在Object/object.c
中发现如下代码,
if (PyType_Ready(&PyFloat_Type) < 0) Py_FatalError("Can't initialize float type");
创建类型对象过程中,需要PyType_Ready
方法将tp_base
字段初始化,具体如下
int PyType_Ready(PyTypeObject *type) { // ... base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { base = type->tp_base = &PyBaseObject_Type; Py_INCREF(base); } // ... }
PyFloat_Type
中的tp_base
字段初始化成PyBaseObject_Type
,它就是object背后的实体,其源码定义为,
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 */ };
源码中ob_type
字段指向PyType_Type
这与下方object在 Python中的测试代码相吻合,
>>> object.__class__ <class 'type'>
此外,PyType_Ready
函数初始化PyBaseObject_Type
时,不设置tp_base
字段。 因为继承链必须有一个终点,否则沿着继承链查找时会陷入死循环。
>>> print(object.__base__) None
由此,得到了实例对象和类型对象在内存中完整的关系图。以float为例,
到此这篇关于Python源码学习之PyType_Type和PyBaseObject_Type详解的文章就介绍到这了,更多相关PyType_Type和PyBaseObject_Type内容请搜索hwidc以前的文章或继续浏览下面的相关文章希望大家以后多多支持hwidc!
【本文转自:襄阳网站优化 欢迎转载】