1 对象原型
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
1.1 PyObject_VAR_HEAD
PyObject_VAR_HEAD是之前讲过的变量类型PyVarObject的宏定义,表明list是一个变量类型。
1.2 ob_item
ob_item是指向PyObject类型的指针的指针。首先说明一下,list是一个容器,里面可以容纳很多PyObject类型的对象。PyListObject用来维护list对象本身的信息,ob_item指向一块连续空间,这块空间装载了n个指针,每一个指针指向一个PyObject对象。
由此可见:List里面并没有真的装载数据,只是在要保存的对象上添加了一条引用。
ob_item的数据结构是顺序表。这决定了list类型insert操作是耗时的操作。
数据大小一致,存储在连续的内存空间中,这种存储结构是顺序表。不同的数据结构,同样的操作性能是不相同的,因此要有不同的算法。
顺序表和链表比起来,通过位置找数据是非常快的,但是插入删除某一节点的开销非常大,需要搬移大块数据。但是顺序表结构简单,占用内存空间小,在list中使用这种结构还是很好的。
Tip:不懂顺序表的自行学习一下,这对于理解list太重要了。“算法+数据结构=程序”至理名言啊
1.3 allocated
allocated表明当前为ob_item分配了多少空间,有别于ob_size,ob_size是当前真正使用了多少空间,这里简单说一下,当你的list变得更长时,每次为ob_item分配空间,并非按需分配,详见list_resize
2 方法
前面我们说过了list对象原型,和使用的数据结构,list的方法主要就是操作list中的数据。核心就是围绕ob_item指向的顺序表展开的。
2.1 list的创建
PyObject *
PyList_New(Py_ssize_t size)
{
PyListObject *op;
#ifdef SHOW_ALLOC_COUNT
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);
#ifdef SHOW_ALLOC_COUNT
count_reuse++;
#endif
} else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL)
return NULL;
#ifdef SHOW_ALLOC_COUNT
count_alloc++;
#endif
}
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;
}
首先说一下,list也有自己的缓冲机制,缓冲池可以容纳80个list对象,对象使用完毕后不会直接销毁,如果缓冲池没有满,就放入缓冲池中,以后新建对象的时候优化使用缓冲池中的对象。这样省去申请内存的开销,用空间换时间。
创建过程:从缓冲池中获取一个对象,如果没有空闲对象则申请一块空间,作为新对象。
为ob_item分配一块指定大小的空间,用来装指针。
维护allocated等其它属性。
2.2 list的插入
int
PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
return ins1((PyListObject *)op, where, newitem);
}
static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
Py_ssize_t i, n = Py_SIZE(self);
PyObject **items;
if (v == NULL) {
PyErr_BadInternalCall();
return -1;
}
if (n == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"cannot add more objects to list");
return -1;
}
if (list_resize(self, n+1) < 0)
return -1;
if (where < 0) {
where += n;
if (where < 0)
where = 0;
}
if (where > n)
where = n;
items = self->ob_item;
for (i = n; --i >= where; )
items[i+1] = items[i];
Py_INCREF(v);
items[where] = v;
return 0;
}
插入过程:
1将要插入的位置以下所有数据下移
2空出位置插入新数据
2.3 list的删除, 修改, 查询
这个留给读者自行学习吧。读懂了insert,这些也都是小case。
3 other
3.1 List最大容量
大家不要以为,list是无穷大的,在阅读代码的时候我们发现。Python已经规定了list的最大容量PY_SSIZE_T_MAX。
#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
(size_t)-1在c语言中表示0xFFFFFFFF。用来表示全1
那么你知道最大值是多少了吗?