从 List 中删除元素与 pop 类似,只不过会将弹出元素直接删除,内存操作及性能大体相同,不再赘述。
List 通过切片快速截取片段,切片需要指定起、止索引,过程也很简单,实现如下:
static PyObject *
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
PyListObject *np;
PyObject **src, **dest;
Py_ssize_t i, len;
len = ihigh - ilow;
np = (PyListObject *) list_new_prealloc(len);
if (np == NULL)
return NULL;
src = a->ob_item + ilow;
dest = np->ob_item;
for (i = 0; i < len; i++) {
PyObject *v = src[i];
Py_INCREF(v);
dest[i] = v;
}
Py_SIZE(np) = len;
return (PyObject *)np;
}
切片实际上是从创建原始 List 片段的副本,而非真的 “切” 片,可能 slice 翻译为 “片段” 更合适。切片的基本逻辑很直接:
- 创建一个空 List;
- 从原始 List 的 start 到 stop,将内容复制到新数组;
特别需要注意的是,空 List 是通过 list_new_prealloc 函数分配,如果还记得之前的内容,PyList_New 也可以创建指定长度的 List, 这里没有直接使用 PyList_New 创建空白 List,主要原因是传入 size 的 PyList_New 函数会同时指定 ob_size,这与实际上 List 中没有任何元素不符。所以 list_new_prealloc 中只是用 PyList_New(0) 创建了 List Object 结构,之后单独创建 ob_item array,这样 ob_size 为 0, allocated 为 size,相当于预分配。
整个过程看起来像这样: