python对象pyObject的源码实现
Posted ybdesire
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python对象pyObject的源码实现相关的知识,希望对你有一定的参考价值。
1. 引入
在python中,基本数据类型,比如整数,是存储在栈中吗?
答案是否定的,python中的数据,都是对象,对象都存储在堆区。
2. 一切都是对象
在Python的世界中,一切都是对象,一个整数是一个对象,一个字符串也是一个对象。更为奇妙的是,类型也是一种对象,整数类型是一个对象,字符串类型也是一个对象;面向对象理论中的“类”和“对象”,都是通过python内的对象来实现的(摘自参考1)。
为什么是这样呢?
因为cpython中,并没有对象这种机制,所以使用struct来定义了python内的对象。也就是说,python的对象,都是通过c语言的struct来实现的。
3. 对象都在堆区被创建
在cpython源码(Python-3.10.4/Include/object.h)中,明确说明了所有对象都是在堆区申请的内存:
Objects are structures allocated on the heap. Special rules apply to
the use of objects to ensure they are properly garbage-collected.
Objects are never allocated statically or on the stack; they must be
accessed through special macros and functions only.
这里也强调了python内的对象永远不可能在栈区申请内存。
4. 对象的结构
python内的对象,是C语言定义一个名为PyObject的struct(参考2),核心源码如下:
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA \\
struct _object *_ob_next; \\
struct _object *_ob_prev;
typedef struct _object
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
PyObject;
我们可以看到:
- 所有对象都会被组成一个双链表,源码注释中就强调了这个
- 对象就是双链表中的一个节点
_ob_prev
和_ob_next
是双链表的前驱、后继节点ob_refcnt
是垃圾回收中的引用计数器,他记录了某个对象被引用的次数,当该数值为0时这个对象就会被垃圾回收器回收ob_type
指向类型对象的指针
5. 有哪些对象
从参考3中,我们可以看到,python中的任何一个类型,都有对应的.h文件来定义这个类型的对象,比如:
- int对象:intobject.h
- boolobject.h
- floatobject.h
- bytesobject.h
- listobject.h
- dictobject.h
- setobject.h
- classobject.h
6. 环状双向链表
所有存活的对象,都组成一个环状双向链表(参考4)。双向链表的头指针名为 refchain 。
为什么是双向链表而非单链表呢?
- 双向链表的优点,在于可以双向索引
- 那么这里是否真的有必要组成双链表呢?笔者通过全文搜索源码中的双链表前驱指针
_ob_prev
,发现源码中其实对双链表前驱遍历的使用非常少,所以单纯从python3.10的C源码来看,笔者认为源码中并没有对双链表的优势做太多有价值的使用
5. 总结
本文讲述了:python中一切都是对象(包括int,string,list),对象都保存在堆区,pyObject的源码以及环状双向链表保存所有存活对象。
6. 参考
- 陈儒,python源码解析
- PyObject源码,https://github.com/python/cpython/blob/3.10/Include/object.h#L105
- https://github.com/python/cpython/tree/3.10/Include
- refchain,https://github.com/python/cpython/blob/3.10/Objects/object.c#L86
以上是关于python对象pyObject的源码实现的主要内容,如果未能解决你的问题,请参考以下文章