Python中list.pop(index)工作原理解析及相关性能疑问
关于Python list.pop(0)的元素移动问题
答案是肯定的:执行pop(0)时,Python会把列表内所有后续元素的指针逐个向前移动,只是这个移动逻辑没有直接写在list_pop_impl函数里,而是封装到了list_ass_slice函数中。
结合你提供的代码具体分析:
- 当要删除的元素不是列表最后一个元素时(比如
pop(0)),代码会调用list_ass_slice(self, index, index+1, (PyObject *)NULL),这个函数的作用是删除列表中[index, index+1)区间的单个元素。 - 在CPython的底层实现里,
list_ass_slice处理非末尾元素删除时,会通过**内存拷贝操作(比如memmove)**把index+1位置到列表末尾的所有指针,整体向前移动一个位置。这和手动写for循环逐个移动指针的效果完全一致,时间复杂度为O(N),也对应了pop(index)(index非末尾)的O(N)时间复杂度。 - 只有删除最后一个元素时,代码调用的
list_resize只是调整列表的长度标记,不需要移动任何元素,所以时间复杂度是O(1)。
附上你提供的list_pop_impl实现代码:
static PyObject * list_pop_impl(PyListObject *self, Py_ssize_t index) /*[clinic end generated code: output=6bd69dcb3f17eca8 input=b83675976f329e6f]*/ { PyObject *v; int status; if (Py_SIZE(self) == 0) { /* Special-case most common failure cause */ PyErr_SetString(PyExc_IndexError, "pop from empty list"); return NULL; } if (index < 0) index += Py_SIZE(self); if (!valid_index(index, Py_SIZE(self))) { PyErr_SetString(PyExc_IndexError, "pop index out of range"); return NULL; } v = self->ob_item[index]; if (index == Py_SIZE(self) - 1) { status = list_resize(self, Py_SIZE(self) - 1); if (status >= 0) return v; /* and v now owns the reference the list had */ else return NULL; } Py_INCREF(v); status = list_ass_slice(self, index, index+1, (PyObject *)NULL); if (status < 0) { Py_DECREF(v); return NULL; } return v; }
内容的提问来源于stack exchange,提问作者helloworld
相关产品推荐
相关产品推荐

