首页 新闻 会员 周边 捐助

L[0] 和 L[0:2]/L[slice(0,2)] 在 CPython 底层走的是两条完全不同的代码路径

0
[已解决问题] 解决于 2025-09-05 10:23

切片一定会新建一个 PyListObject;单个索引只是返回已有对象的引用

>>> import dis
>>> dis.dis(lambda: L[0])
  1           0 LOAD_GLOBAL              0 (L)
              2 LOAD_CONST               0 (0)
              4 BINARY_SUBSCR
              6 RETURN_VALUE

>>> dis.dis(lambda: L[0:2])
  1           0 LOAD_GLOBAL              0 (L)
              2 LOAD_CONST               0 (0)
              4 LOAD_CONST               1 (2)
              6 BUILD_SLICE              2
              8 BINARY_SUBSCR
             10 RETURN_VALUE

  • L[0] 直接把整数 0 当成下标走 BINARY_SUBSCR
  • L[0:2]BUILD_SLICE 生成 slice 对象,再走 BINARY_SUBSCR
_java_python的主页 _java_python | 小虾三级 | 园豆:984
提问于:2025-09-05 10:21
< >
分享
最佳答案
0
  1. static PyObject *
    list_subscript(PyListObject *self, PyObject *key)
    {
        if (PySlice_Check(key)) {          // ① 切片分支
            Py_ssize_t start, stop, step, slicelength;
            if (PySlice_Unpack(key, &start, &stop, &step) < 0)
                return NULL;
            slicelength = PySlice_AdjustIndices(Py_SIZE(self),
                                                &start, &stop, step);
    
            /* 新建一个 list,大小=slicelength */
            PyListObject *np = (PyListObject *) PyList_New(slicelength);
            if (!np) return NULL;
    
            /* 逐个 PyList_SET_ITEM 拷贝引用 */
            for (Py_ssize_t i = 0; i < slicelength; ++i) {
                PyObject *v = self->ob_item[start];
                Py_INCREF(v);
                PyList_SET_ITEM(np, i, v);
                start += step;
            }
            return (PyObject *)np;
        }
        else {                              // ② 单索引分支
            Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
            if (i == -1 && PyErr_Occurred())
                return NULL;
            if (i < 0 || i >= Py_SIZE(self)) {
                PyErr_SetString(PyExc_IndexError, "list index out of range");
                return NULL;
            }
            PyObject *v = self->ob_item[i];
            Py_INCREF(v);
            return v;                       // 只增加一次引用计数,直接返回
        }
    }

     

    CPython 内部实现(Objects/listobject.c)
BINARY_SUBSCR 最终会调到
list_subscript(PyListObject *self, PyObject *key)
L[0] 只返回已有元素引用
 
_java_python | 小虾三级 |园豆:984 | 2025-09-05 10:22
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册