我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python源码学习之PyObject和PyTypeObject

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python源码学习之PyObject和PyTypeObject

前言

Python是C语言实现的,因此Python对象在C语言层面应该是一个结构体 ,组织对象占用的内存。 不同类型的对象,数据及行为均可能不同,因此可以大胆猜测:不同类型的对象由不同的结构体表示

对象也有一些共性,比如每个对象都需要有一个引用计数,用于实现垃圾回收机制。因此,还可以进一步猜测:表示对象的结构体有一个公共头部

一. 实例对象的基石—PyObject和PyVarObject

PyObject和PyVarObject本质上是对象的头部信息

1.1 PyObject结构体

Python对象都由PyObject结构体表示,对象引用则是指针PyObject *PyObject结构体定义于头文件object.h,路径为Include/object.h,代码如下


typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

对结构体中的元素进行说明,

元素名称 说明
ob_refcnt 引用计数,对象被其他地方引用时加一,引用解除时减一; 当引用计数为零,便可将对象回收,这是最简单的垃圾回收机制。
ob_type 类型指针指向对象的类型对象,类型对象描述实例对象的数据及行为。
_PyObject_HEAD_EXTRA 宏,同样定义在Include/object.h头文件内。

1.2 宏的定义


#ifdef Py_TRACE_REFS

#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

如果Py_TRACE_REFS被定义,宏展开为两个指针ob_nextob_prev用来实现双向链表。注释中说明,双向链表用于跟踪所有活跃堆对象,一般不启用,不深入介绍。

1.3 PyVarObject结构体

用于表示变长对象PyVarObject结构体是在PyObject结构体的基础上加入长度信息。


typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; 
} PyVarObject;

相比object结构体增加了ob_size字段用于记录元素个数。

Alt

1.4 两种头部信息宏定义及其初始化

具体实例对象视其内存大小是否固定,决定其属于定长对象还是变长对象。相应的需要具有头部信息PyObjectPyVarObject

因此,头文件准备了两个头部信息的宏定义PyObject_HEADPyObject_VAR_HEAD,方便对象使用,


#define PyObject_HEAD          PyObject ob_base;
#define PyObject_VAR_HEAD      PyVarObject ob_base;

宏定义说明,


#define PyObject_HEAD PyObject ob_base;
表示将代码中其他出现PyObject_HEAD的地方,替换成PyObject ob_base;

1.4.1 定长对象实现

内存大小固定的浮点数类的实现只需在PyObject头部基础上,用一个双精度浮点数double加以实现,


typedef struct {
    PyObject_HEAD

    double ob_fval;
} PyFloatObject;

Alt

1.4.2 变长对象实现

内存大小不固定的列表对象则需要在PyVarObject头部的基础上,用一个动态数组加以实现,数组存储列表包含的对象,即 PyObject 指针,


typedef struct {
    PyObject_VAR_HEAD

    PyObject **ob_item;
    Py_ssize_t allocated;
} PyListObject;

Alt

PyListObject底层由一个数组实现,关键字段是以下3个,

字段 说明
ob_item 指向动态数组的指针,数组保存元素对象指针。
allocated 动态数组总长度,即列表当前的 容量。
ob_size 当前元素个数,即列表当前的 长度。

列表容量不足时,Python会自动扩容,具体机制见list源码解读。

1.4.3 头部信息宏初始化

PyObject_HEAD_INIT用于定长对象头部信息初始化。将引用计数ob_refcnt设置为1并将对象类型ob_type设置成给定类型。


#define PyObject_HEAD_INIT(type)        \
    { _PyObject_EXTRA_INIT              \
    1, type },

PyVarObject_HEAD_INIT用于变长对象头部信息初始化。在前者基础上进一步设置长度字段ob_size


#define PyVarObject_HEAD_INIT(type, size)       \
    { PyObject_HEAD_INIT(type) size },

在源码中经常见到这两个宏定义。

二. 类型对象的基石—PyTypeObject 2.1 PyTypeObject包含信息

PyObject记录了Python中所有对象共有的信息。如引用计数、类型指针和变长对象特有的元素个数。但是还有一些细节需要考虑,

  • 创建不同类型的对象时如何得知对象所需的内存信息
  • 给定某个对象,如何判断它支持什么操作

这些作为对象的元信息 ,应该由一个独立实体保存,与对象所属类型密切相关。PyObject中包含的ob_type指针,指向一个类型对象。类型对象PyTypeObject也在Include/object.h中定义,关键字段如下,


typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; 
    Py_ssize_t tp_basicsize, tp_itemsize; 

    
    destructor tp_dealloc;
    printfunc tp_print;

    getattrfunc tp_getattr;
    setattrfunc tp_setattr;

    // ...
    
    struct _typeobject *tp_base;

    // ......
} PyTypeObject;

类型对象PyTypeObject是一个变长对象,包含变长对象头部信息PyObject_VAR_HEAD和专有字段,

字段 说明
类型名称 tp_name字段
类型的继承信息 tp_base字段指向基类对象
创建实例对象时所需的内存信息 tp_basicsize 和 tp_itemsize 字段
该类型支持的相关操作信息 tp_print、tp_getattr等函数指针

PyTypeObject就是类型对象在 Python 中的表现形式,对应着面向对象中“类”的概念。PyTypeObject结构很复杂,目前只需要知道它保存着对象的元信息,描述对象的类型即可。

2.2 类型对象和实例对象在内存中的关系

以float为例,考察类型对象和实例对象在内存中的形态和关系,


>>> float
<class 'float'>
>>> pi = 3.14
>>> e = 2.71
>>> type(pi) is float
True

Alt

  • 两个float实例对象都是PyFloatObject结构体,除了公共头部字段ob_refcntob_type,专有字段ob_fval保存了对应的数值。
  • 类型对象是一个PyTypeObject结构体,保存了类型名、内存分配信息以及浮点数相关操作。实例对象的ob_type字段指向类型对象,Python 据此判断对象类型,进而获悉关于对象的元信息。
  • float、pi以及e等变量只是一个指向实际对象的指针。

上图的内容并不完全正确,更深入的解读见后一篇博文。

到此这篇关于Python源码学习之PyObject和PyTypeObject的文章就介绍到这了,更多相关PyObject和PyTypeObject内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python源码学习之PyObject和PyTypeObject

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python源码剖析之PyObject的示例分析

这篇文章主要介绍python源码剖析之PyObject的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Python中的对象Python中一切皆是对象。————Guido van Rossum(1989)这
2023-06-15

Python学习手册之Python异常和

在上一篇文章中,我们介绍了 Python 的函数和模块,现在我们介绍 Python 中的异常和文件。查看上一篇文章请点击:https://www.cnblogs.com/dustman/p/9963920.html异常和文件异常异常也叫例外
2023-01-30

python学习之-获取get和post

1.python接收get请求里的参数req = request.args.get('xxx')2.python接收post请求里的参数req = request.form.get('xxx')
2023-01-31

python学习之map函数和reduc

MapReduce:面向大型集群的简化数据处理   引文map()函数Python中的map()函数接收两个参数,一个是调用函数对象(python中处处皆对象,函数未实例前也可以当对象一样调用),另一个是调用函数所需要的参数,返回值是迭代计
2023-01-30

Python学习之进程和并发

从Python2.4 以后,subprocess模块负责衍生出新的进程,和标准输入,标准输出,标准错误输出交互,并监听返回值。Subprocess模块是用来取代一些老的模块,例如os.system, os.spawn, os.popen和p
2023-01-31

elementui源码学习之仿写一个el-divider组件

这篇文章主要为大家介绍了elementui源码学习之仿写一个el-divider组件示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Webpack学习之动态import原理及源码分析

这篇文章主要为大家介绍了Webpack学习之动态import原理及源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录