目录
1.初识PyListObject
python里的列表不是书上基于链表的列表,而是基于可变长度的数组。PyListObject对象可以有效支持元素插入添加删除等操作,它的定义为:
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
ob_item指针指向元素列表所在内存块首地址,而allocated中则维护了当前列表中可容纳的元素总数。我们知道PyObject_VAR_HEAD中有一个ob_size,它维护的是当前列表中已容纳的元素数量。
2.PyListObject对象的创建和维护
2.1创建对象
PyObject *PyList_New(Py_ssize_t size)
{
PyListObject *op;
static int initialized = 0;
if (!initialized) {
Py_AtExit(show_alloc);
initialized = 1;
}
#endif
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
if (numfree) {
缓冲池可用
numfree--;
op = free_list[numfree];
_Py_NewReference((PyObject *)op);
count_reuse++;
} else {
缓冲池不可用
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL)
return NULL;
count_alloc++;
}
if (size <= 0)
op->ob_item = NULL;
else {
为列表申请内存空间
op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *));
if (op->ob_item == NULL) {
Py_DECREF(op);
return PyErr_NoMemory();
}
}
Py_SIZE(op) = size;
op->allocated = size;
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}
从上面的创建动作我们可以看出,列表对象实际上分为两部分,一是PyListObject对象本身,二是PyListObject对象维护的元素列表,这是两块分离的内存,通过ob_item建立联系。
另外,创建新的PyListObject对象时我们可以看到非常熟悉的缓冲池技术。在创建PyListObject时,会先检查缓冲池free_list中是否有可用的对象。如果有,则直接使用,否则通过PyObject_GC_New咋系统堆中申请内存,创建新的PyListObject。
在python3.7.5中,默认情况下,free_list最多只有80个PyListObject对象。
#define PyList_MAXFREELIST 80
#endif
static PyListObject *free_list[PyList_MAXFREELIST];
static int numfree = 0;
2.2设置元素
假设我们创建一个包含6个元素的PyListObject,它的内存图如下:
注意创建一个list时列表元素不可能是null,这里只是为了演示元素变化。假设我们在第4个位置添加100,添加过程如下:
int
PyList_SetItem(PyObject *op, Py_ssize_t i,
PyObject *newitem)
{
PyObject **p;
if (!PyList_Check(op)) {
Py_XDECREF(newitem);
PyErr_BadInternalCall();
return -1;
}
【1】索引检查
if (i < 0 || i >