Python进阶编程:编写更高效、优雅的Python代码
上QQ阅读APP看书,第一时间看更新

3.1.1 序列对象解析

Python提供的列表的抽象对象为PyListObject,即List对象。List对象是一个变长对象,在运行时动态调整其所维护的内存和元素,并且支持插入、删除等操作。

PyListObject对象源码(Include/listobject.h)结构如下:


// Include/listobject.h
typedef struct {
    PyObject_VAR_HEAD       // 变量头部信息 
    
    PyObject **ob_item;     // 元素指向具体值

    Py_ssize_t allocated;   // 当前空间
} PyListObject;

结合可变对象的源码(Include/object.h)如下:


// Include/object.h

typedef struct _object {
    _PyObject_HEAD_EXTRA            // 双向链表 垃圾回收 需要用到
    Py_ssize_t ob_refcnt;           // 引用计数
    struct _typeobject *ob_type;    // 指向类型对象的指针,决定了对象的类型
} PyObject;

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

上述源码中,ob_size和allocated都和PyListObject对象的内存管理有关。ob_size表示列表实际拥有的元素数量,allocated表示实际申请的内存空间,比如列表A实际申请了5个元素的空间,但此时A只包含2个元素,则ob_size为2,allocated为5。

生成新的List对象时,首先检查缓冲池是否有List对象,若没有,则新生成一个List对象。新建的List对象默认维护80个PyListObject对象,源码(Object/Listobject.c)如下:


// Object/listobject.c

#define PyList_MAXFREELIST 80
#endif
static PyListObject *free_list[PyList_MAXFREELIST];
static int numfree = 0;

每次对序列对象添加元素时,都会调整列表的大小。在调整列表大小后,如果传入的负值索引比列表长度还大,则传入值设置在0位;如果传入的正值索引比列表长度还大,则传入值设置为最后一位,并将大于索引值的元素往后移动一位。这就是序列插入的大致过程。

这里对序列的源码做一些简单讲解,对序列源码感兴趣的读者可以重点查看Include/listobject.h和Object/listobject.c这两个文件。序列的创建、插入、删除、调整等的源码实现都在Object/listobject.c文件中。