08月15, 2020

18. List 切片

从 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,相当于预分配。

整个过程看起来像这样: gif

本文链接:http://www.thinkinpython.com/post/deep_python_vm_18.html

-- EOF --