Python源码学习之PyType_Type和PyBaseObject_Type详解

作者:Jakob_Hu 时间:2023-08-03 15:50:05 

PyType_Type和PyBaseObject_Type

PyObject和PyTypeObject内容的最后指出下图中对实例对象类型对象的理解是不完全正确的,

Python源码学习之PyType_Type和PyBaseObject_Type详解

浮点类型对象全局唯一,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_refcntob_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_TypePyTypeObject的一个实例。

  • PyType_Type是类型机制中至关重要的对象,是所有类型的类型,称为元类型

  • 第2行代码处PyType_Type将自身的ob_type字段指向它自己。


>>> type.__class__
<class 'type'>
>>> type.__class__ is type
True

由此,以float为例,可以绘制一个更完善但是并不完全正确的实例对象和类型对象在内存中的关系图,

Python源码学习之PyType_Type和PyBaseObject_Type详解

二. 类型之基—PyBaseObject_Type(object的实体)

上一节中红色标记的语句,并不完全正确是因为思考过程中忽略了object对象的存在。

object是另一个特殊的类型,是所有类型的基类。同样可以通过PyFloat_Typetp_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详解

来源:https://blog.csdn.net/Jakob_Hu/article/details/117913750

标签:Python,PyType,Type,PyBaseObject,Type
0
投稿

猜你喜欢

  • 基于Git的常用撤销技巧与解决冲突方法(推荐)

    2023-07-01 19:20:28
  • window系统mysql无法输入和无法显示中文的解决方法

    2024-01-20 05:13:29
  • [译]2009年海外Web设计风潮(上)

    2009-01-23 09:21:00
  • Python基于keras训练实现微笑识别的示例详解

    2022-06-14 10:02:07
  • 十个免费的web前端开发工具详细整理

    2023-08-12 17:01:22
  • 滑动验证码的设计与理解

    2022-09-18 08:34:28
  • 一文弄懂MySQL索引创建原则

    2024-01-14 07:38:25
  • python使用QQ邮箱实现自动发送邮件

    2021-03-03 22:10:06
  • Flask中jinja2的继承实现方法及实例

    2022-09-24 12:31:09
  • 使用微信助手搭建微信返利机器人流程

    2022-10-10 08:34:03
  • 使用Python轻松完成垃圾分类(基于图像识别)

    2023-06-24 06:06:47
  • Javascript 回调和事件(翻译)

    2009-03-28 11:47:00
  • 一个入门级python爬虫教程详解

    2023-03-27 17:34:08
  • python爬取一组小姐姐图片实例

    2023-08-03 15:05:45
  • 你真的了解触发器么 数据实时同步更新问题剖析

    2024-01-24 00:48:40
  • python批量telnet检测IP地址的端口是否开放

    2023-12-28 12:12:24
  • python中__call__方法示例分析

    2023-01-16 04:31:31
  • 如何在Django中设置定时任务的方法示例

    2023-03-21 06:19:07
  • 当设计师遇上前端开发

    2009-05-04 14:05:00
  • PHP字典树(Trie树)定义与实现方法示例

    2023-11-15 00:39:50
  • asp之家 网络编程 m.aspxhome.com