• 技术文章 >Python技术 >Python基础教程

    Python中对切片赋值原理分析

    PythonPython2019-06-03 15:39:40原创3435
    有这么个问题::

    t = [1, 2, 3]
    t[1:1] = [7] 
    print t  # 输出 [1, 7, 2, 3]

    谁会对列表这么进行赋值呢?但是对于这个输出结果的原因确实值得去再了解下,今天看看Python的源码,了解下原理是什么。

    注:本地下载的是Python2.7.6的代码,直接看这个。

    在Objects/listobject.c中有一个 PyList_SetSlice 函数,是这么写的::

    int
    PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
    {
        if (!PyList_Check(a)) {
            PyErr_BadInternalCall();
            return -1;
        }
        return list_ass_slice((PyListObject *)a, ilow, ihigh, v);
    }

    有用的一句就是 list_ass_slice ,那么再来看看这个函数的代码::

    static int
    list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
    {
        /* Because [X]DECREF can recursively invoke list operations on
        this list, we must postpone all [X]DECREF activity until
        after the list is back in its canonical shape.  Therefore
        we must allocate an additional array, 'recycle', into which
        we temporarily copy the items that are deleted from the
        list. :-( */
        PyObject *recycle_on_stack[8];
        PyObject **recycle = recycle_on_stack; /* will allocate more if needed */
        PyObject **item;
        PyObject **vitem = NULL;
        PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */
        Py_ssize_t n; /* # of elements in replacement list */
        Py_ssize_t norig; /* # of elements in list getting replaced */
        Py_ssize_t d; /* Change in size */
        Py_ssize_t k;
        size_t s;
        int result = -1;            /* guilty until proved innocent */
    #define b ((PyListObject *)v)
        if (v == NULL)
            n = 0;
        else {
            if (a == b) {
                /* Special case "a[i:j] = a" -- copy b first */
                v = list_slice(b, 0, Py_SIZE(b));
                if (v == NULL)
                    return result;
                result = list_ass_slice(a, ilow, ihigh, v);
                Py_DECREF(v);
                return result;
            }
            v_as_SF = PySequence_Fast(v, "can only assign an iterable");
            if(v_as_SF == NULL)
                goto Error;
            /*
            要赋值的长度n
            */
            n = PySequence_Fast_GET_SIZE(v_as_SF);
            vitem = PySequence_Fast_ITEMS(v_as_SF);
        }
        if (ilow < 0)
            ilow = 0;
        else if (ilow > Py_SIZE(a))
            ilow = Py_SIZE(a);
        if (ihigh < ilow)
            ihigh = ilow;
        else if (ihigh > Py_SIZE(a))
            ihigh = Py_SIZE(a);
        norig = ihigh - ilow;
        assert(norig >= 0);
        d = n - norig;
        if (Py_SIZE(a) + d == 0) {
            Py_XDECREF(v_as_SF);
            return list_clear(a);
        }
        item = a->ob_item;
        /* recycle the items that we are about to remove */
        s = norig * sizeof(PyObject *);
        if (s > sizeof(recycle_on_stack)) {
            recycle = (PyObject **)PyMem_MALLOC(s);
            if (recycle == NULL) {
                PyErr_NoMemory();
                goto Error;
            }
        }
        memcpy(recycle, &item[ilow], s);
        if (d < 0) { /* Delete -d items */
            memmove(&item[ihigh+d], &item[ihigh],
                (Py_SIZE(a) - ihigh)*sizeof(PyObject *));
            list_resize(a, Py_SIZE(a) + d);
            item = a->ob_item;
        }
        else if (d > 0) { /* Insert d items */
            k = Py_SIZE(a);
            if (list_resize(a, k+d) < 0)
                goto Error;
            item = a->ob_item;
            printf("关键点\n");
            /*
            把list对应切片后一位的值之后的所有内容向后移动所赋值的大小
            按照上面的python代码这里就是
            原理的t:
            |1|2|3|
            后移一位,因为len([7]) = 1
            |1|空|2|3|把后两个移位
            */
            memmove(&item[ihigh+d], &item[ihigh],
                (k - ihigh)*sizeof(PyObject *));
        }
        /*
        赋值操作,即把[7]赋值到t里的对应位置上
        ilow是1, n是1
        */
        for (k = 0; k < n; k++, ilow++) {
            PyObject *w = vitem[k];
            Py_XINCREF(w);
            item[ilow] = w;
        }
        for (k = norig - 1; k >= 0; --k)
            Py_XDECREF(recycle[k]);
        result = 0;
    Error:
        if (recycle != recycle_on_stack)
            PyMem_FREE(recycle);
        Py_XDECREF(v_as_SF);
        return result;
    #undef b
    }

    源码内有详细注释,编程问题的研究最好的解释还是源码。

    专题推荐:python
    品易云
    上一篇:Python中的文件读写-实际操作 下一篇:如何在Python中对dicts列表进行排序

    相关文章推荐

    • python中的去除重复项的操作• python的sort()排序方法• Python中的文件读写-理论知识

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网