这篇文章主要讲解了“在python中PyType_Type和PyBaseObject_Type有什么区别”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“在python中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
。
上文中,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为例,可以绘制一个更完善但是并不完全正确的实例对象和类型对象在内存中的关系图,
上一节中红色标记的语句,并不完全正确是因为思考过程中忽略了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有什么区别”的内容了,经过本文的学习后,相信大家对在python中PyType_Type和PyBaseObject_Type有什么区别这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。