python 内核分析(六):List类型对象

本系列作为本人@takooctopus深入学习python机制的记录,这个博客遵照着栖迟于一丘的博客上面的流程进行的,也包含我在实际查看源码时的感想,特此列出,表示感谢。

关于List对象

我们首先去[Include/listobject.h]中去寻找列表对象的定义:


{{- code -}}

其中有三个属性,PyObject_VAR_HEAD是指向了一个list元素,以及一个二级指针**ob_item储存了这个指针的地址。还有一个allocated储存分配的内存大小。


{{- code -}}

我们可以看见PyObject_VAR_HEAD指向了一个PyVarObject,即其指向了这个元素的第一个,我们通俗地看就是list[0]就是ob_item[0]

我们看指向的PyVarObject,其中的属性ob_size就代表了当前列表的个数len(list)

我们要注意的是,其会申请一块较大的内存,及我们有0 <= ob_size <= allocated关系。

但当列表元素为NULL时,整个内存分配会直接降为0,此时有,ob_size == allocated == 0

PyListObject 方法

我们可以看见在这个Object类中的方法:


{{- code -}}

PyListObject的创建

列表的创建我们使用的是PyList_New()


{{- code -}}

我们在这里看见了numfree这个属性,返回去看,发现其与一个列表free_list[]有关,称其为freelist,也可以叫其为缓冲池。其常量定义在最前面:


{{- code -}}

在缓冲池有剩余时,新建一个list对象,会直接从缓冲区freelist[]中直接初始化,缓冲池不可用的时候,就会调用PyObject_GC_New()直接新建。

默认情况下,缓冲区最大有PyList_MAXFREELIST = 80个对象。

PyObject_GC_New()_PyObject_GC_New()的别名:


{{- code -}}

其为这个对象类型分配内存。

而关于缓冲区freelist[]的函数其实只有三个,另外俩一个是PyList_ClearFreeList(),用以清除所有的缓冲区;还有一个是list_dealloc(),其作用是PyListType对象的析构操作。

奇怪的是,其会在释放掉PyListObject *op中维护的所有对象后,视情况将其放入缓冲区或者直接释放掉。这应该是为了保证缓冲区在结束后有足够的大小。

PyListObject的元素设置


{{- code -}}

在进行了类型和越界检查后,平移指针找到需要替换的位置,替换为新的对象。在Py_XSERREF()中我们能看见其将原本对象的引用进行检查,必要时施行销毁操作。

PyListObject获取元素


{{- code -}}

PyListObject的插入操作


{{- code -}}

简单地处理了插入时的越界和负索引「如果负索引过小于-n会直接置零」后,确定插入位置,后面的元素统一后移一个位置。

PyListObject的附加操作


{{- code -}}

和上面的添加操作差不多

PyListObject的删除操作


{{- code -}}

python会在遍历列表后删除找到第一个匹配的元素,并在找不到时返回异常。

其他操作

此外PyListObject还有很多方法,比如merge相关,reverse相关和sort相关等等,这些在以后再写。