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定义中,该字段并没有初始化,
更进一步查找代码中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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:- Python源码学习之PyObject和PyTypeObject
- Python源码解析之List
- python源码剖析之PyObject详解
- python opencv人脸识别考勤系统的完整源码
- python 制作手机归属地查询工具(附源码)
- python基于tkinter制作无损音乐下载工具(附源码)
- Python bsonrpc源码解读
- Python制作脚本帮女朋友抢购清空购物车