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 Foo(object):...pass...>>> Foo.__class__
【Python源码学习之PyType_Type和PyBaseObject_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__>>> type.__class__ is typeTrue
由此,以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
字段初始化,具体如下intPyType_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__
此外,
PyType_Ready
函数初始化PyBaseObject_Type
时,不设置tp_base
字段。 因为继承链必须有一个终点,否则沿着继承链查找时会陷入死循环。>>> print(object.__base__)None
由此,得到了实例对象和类型对象在内存中完整的关系图。以float为例,
文章图片
到此这篇关于Python源码学习之PyType_Type和PyBaseObject_Type详解的文章就介绍到这了,更多相关PyType_Type和PyBaseObject_Type内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 慢慢的美丽
- 开学第一天(下)
- 奔向你的城市
- 学无止境,人生还很长
- 由浅入深理解AOP
- “成长”读书社群招募
- 继续努力,自主学习家庭Day135(20181015)
- python学习之|python学习之 实现QQ自动发送消息
- 每日一话(49)——一位清华教授在朋友圈给大学生的9条建议
- 小影写在2018九月开学季