首页 > 代码库 > 《python源码剖析》笔记 python中的List对象

《python源码剖析》笔记 python中的List对象

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie


1.PyListObject对象 --> 变长可变对象,可看作vector<PyObject *>

typedef struct{
	PyObject_VAR_HEAD //其中的ob_size表示实际被使用的内存的数量
	PyObject **ob_item;//ob_item为指向元素列表的指针,实际上,Python中的list[0]就是ob_item[0]
	int allocated;//当前列表中可容纳的元素的总数
}
PyList_Type 对象 --> PyListObject的类型对象
typedef struct{
	PyObject_VAR_HEAD //其中的ob_size表示实际被使用的内存的数量
	PyObject **ob_item;//ob_item为指向元素列表的指针,实际上,Python中的list[0]就是ob_item[0]
	int allocated;//当前列表中可容纳的元素的总数
}
2.创建PyListObject对象
一种途径:
PyObject *PyList_New(int size)
1.内存数量计算,溢出检查
2.为PyListObject对象申请空间
3.为PyListObject对象中维护的元素列表申请空间

PyListObject缓冲池,缓存的只是PyListObject *
#define MAXFREELISTS 80
static PyListObject *free_lists[MAXFREELISTS]
static int num_free_lists = 0;
在第一个PyListObject创建的时候,num_free_lists是0,
会调用 PyObject_GC_New在系统堆上创建一个新的PyListObject对象
当一个PyListObject被销毁时,它会被缓存到PyListObject缓冲池中
如果创建的不是第一个PyListObject时,会检查num_free_lists是否为0,
如果不是的话,在缓冲池中的PyListObject对象会被重新唤醒,重新分配PyObject *
元素列表占用内存,而num_free_lists也会相应的减一。

设置元素
int
PyList_SetItem(register PyObject *op, register Py_ssize_t i,
               register PyObject *newitem)
{
    register PyObject *olditem;
    register PyObject **p;
    if (!PyList_Check(op)) {
        Py_XDECREF(newitem);
        PyErr_BadInternalCall();
        return -1;
    }
	//[1]:索引检查
    if (i < 0 || i >= Py_SIZE(op)) {
        Py_XDECREF(newitem);
        PyErr_SetString(PyExc_IndexError,
                        "list assignment index out of range");
        return -1;
    }
	//[2]:设置元素
    p = ((PyListObject *)op) -> ob_item + i;
    olditem = *p;
    *p = newitem;
    Py_XDECREF(olditem);//注意要将旧元素的引用减一,好让GC自动回收olditem所指向的内存
						//用Py_XDECREF,而不用Py_DECREF是因为olditem有可能是NULL
    return 0;
}
插入元素

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;
    }
	//[1]:调整列表容量
    if (list_resize(self, n+1) == -1)
        return -1;
	//[2]:确定插入点
    if (where < 0) {
        where += n;
        if (where < 0)
            where = 0;
    }
    if (where > n)
        where = n;
	//[3]:插入元素
    items = self->ob_item;
    for (i = n; --i >= where; )
        items[i+1] = items[i];
    Py_INCREF(v); //因为多了一个指向v的指针,所以要增加v的引用数目
    items[where] = v;
    return 0;
}


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
list_resize(PyListObject *self, Py_ssize_t newsize)
{
    PyObject **items;
    size_t new_allocated;
    Py_ssize_t allocated = self->allocated;


	//如果newsize < allocated && newsize > allocated/2,就不需要重新申请内存
    if (allocated >= newsize && newsize >= (allocated >> 1)) {
        assert(self->ob_item != NULL || newsize == 0);
        Py_SIZE(self) = newsize;
        return 0;
    }

    new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);


    /* check for integer overflow */
    //...
	
    if (newsize == 0)
        new_allocated = 0;
	//扩展列表
    items = self->ob_item;
    PyMem_RESIZE(items, PyObject *, new_allocated);//最终调用C中的realloc
    
    self->ob_item = items;
    Py_SIZE(self) = newsize;
    self->allocated = new_allocated;
    return 0;
}

图4-4

删除元素
比较操作
int PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)

/* a[ilow:ihigh] = v if v != NULL.
 * del a[ilow:ihigh] if v == NULL.
 * 当v!=NULL时,用v替换a[ilow:ihigh]
 * 当v == NULL时,删除a[ilow:ihigh]
 */
static int
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)

图4-7

图4-8


3.PyListObject对象缓冲池
static void list_dealloc(PyListObject *op)

1.销毁PyListObject对象维护的元素列表。对list中的每一个元素改变其引用计数,然后将内存释放
2.释放PyListObject自身。查看缓存的PyListObject的数量是否已经满了,如果没有,就将该待删除的PyListObject
对象放到缓冲池,以备后用。缓冲的仅仅是PyListObject对象,而没有这个对象曾经拥有的PyObject *元素列表
图4-9
4.Hack PyListObject
图4-10