《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
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。