listobject
PyListObject
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
PyObject **ob_item;
:列表元素指针存储的地方。Py_ssize_t allocated
:列表分配的空间,不是指元素的个数,元素的个数在PyObject_VAR_HEAD
的ob_size
字段中。
PyList_New
初始化列表
PyObject *
PyList_New(Py_ssize_t size)
{
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
struct _Py_list_state *state = get_list_state();
PyListObject *op;
#ifdef Py_DEBUG
// PyList_New() must not be called after _PyList_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree) {
state->numfree--;
op = state->free_list[state->numfree];
_Py_NewReference((PyObject *)op);
}
else {
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL) {
return NULL;
}
}
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_SET_SIZE(op, size);
op->allocated = size;
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}
struct _Py_list_state
:列表缓冲池对象struct _Py_list_state { PyListObject *free_list[PyList_MAXFREELIST]; int numfree; };
- free_list:空闲列表的指针数组。
- numfree:缓冲池存在的空闲list对象数量。
- Python首先检查缓冲池中是否有空闲对象,如果没有,则通过
PyObject_GC_New
函数创建一个,PyObject_GC_New
对对象的垃圾回收机制有作用。 - 如果为列表元素分配的空间大小为0,则是空列表
op->ob_item = NULL
,否则分配大小为size, sizeof(PyObject *)
的空间。
PyList_SetItem
为列表设置元素
int
PyList_SetItem(PyObject *op, Py_ssize_t i,
PyObject *newitem)
{
PyObject **p;
if (!PyList_Check(op)) {
Py_XDECREF(newitem);
PyErr_BadInternalCall();
return -1;
}
if (!valid_index(i, Py_SIZE(op))) {
Py_XDECREF(newitem);
PyErr_SetString(PyExc_IndexError,
"list assignment index out of range");
return -1;
}
p = ((PyListObject *)op) -> ob_item + i;
Py_XSETREF(*p, newitem);
return 0;
}
- 首先进行类型检查
- 然后进行索引检查,检查是否越界。
((PyListObject *)op) -> ob_item + i;
:索引i的内存地址。Py_XSETREF(*p, newitem);
:设置元素,引用计数+1。
PyList_Insert
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);
}
检查传入参数类型后调用ins1函数。
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; } assert((size_t)n + 1 < PY_SSIZE_T_MAX); 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; }
- 判断传入的
PyObject *v
是否为NULL。 - 断言n+1不会比PY_SSIZE_T_MAX大。
PY_SSIZE_T_MAX = ((Py_ssize_t)(((size_t)-1)>>1))
list_resize
:检查列表空间大小,任何对列表空间操作都会调用list_resize
函数,该函数在需要的时候扩展内存空间或者缩小内存空间,确保内存的利用是最佳的。- 由于Python支持负数索引,所以需要在底层更改为正数。
- 移动元素,可知Python insert操作的时间复杂度为O(n)。
- 引用计数+1,插入元素。
PyList_Append
末尾添加元素
int
PyList_Append(PyObject *op, PyObject *newitem)
{
if (PyList_Check(op) && (newitem != NULL))
return app1((PyListObject *)op, newitem);
PyErr_BadInternalCall();
return -1;
}
static int
app1(PyListObject *self, PyObject *v)
{
Py_ssize_t n = PyList_GET_SIZE(self);
assert (v != NULL);
assert((size_t)n + 1 < PY_SSIZE_T_MAX);
if (list_resize(self, n+1) < 0)
return -1;
Py_INCREF(v);
PyList_SET_ITEM(self, n, v);
return 0;
}
- list_resize对空间大小进行处理后,直接调用
PyList_SET_ITEM
,添加元素。
list_remove
删除元素
static PyObject *
list_remove(PyListObject *self, PyObject *value)
/*[clinic end generated code: output=f087e1951a5e30d1 input=2dc2ba5bb2fb1f82]*/
{
Py_ssize_t i;
for (i = 0; i < Py_SIZE(self); i++) {
PyObject *obj = self->ob_item[i];
Py_INCREF(obj);
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0) {
if (list_ass_slice(self, i, i+1,
(PyObject *)NULL) == 0)
Py_RETURN_NONE;
return NULL;
}
else if (cmp < 0)
return NULL;
}
PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");
return NULL;
}
list_remove
先使用for循环,对列表中的每一个元素进行比较。找到后调用
list_ass_slice
函数进行删除。list_ass_slice
不是专门的删除函数,它有两个功能:if v == null: del a[low:high]
if v != null: v[low:high] = v
list_dealloc
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_BEGIN(op, list_dealloc)
if (op->ob_item != NULL) {
/* Do it backwards, for Christian Tismer.
There's a simple test case where somehow this reduces
thrashing when a *very* large list is created and
immediately deleted. */
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_Free(op->ob_item);
}
struct _Py_list_state *state = get_list_state();
#ifdef Py_DEBUG
// list_dealloc() must not be called after _PyList_Fini()
assert(state->numfree != -1);
#endif
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
state->free_list[state->numfree++] = op;
}
else {
Py_TYPE(op)->tp_free((PyObject *)op);
}
Py_TRASHCAN_END
}
PyObject_GC_UnTrack(op); Py_TRASHCAN_BEGIN(op, list_dealloc)
:Python的内存回收机制。- 在第一个if里减少列表元素的引用计数,释放ob_item内存空间。
第二个if,判断列表缓冲池是否已满,没满则将该空列表放入缓冲池。已满则释放。
>>> a = [1,2,4] >>> b = [1] >>> id_a=id(a) >>> id_b=id(b) >>> id_a 2074874053808 >>> id_b 2074874243712 >>> del a >>> c = [] >>> id_c = id(c) >>> id_a == id_c True >>>
Comments | NOTHING