【www.bbyears.com--python】
本文主要介绍的关于Python切片赋值的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:
昨天有同学问了我这么个问题:
代码如下
t=[1,2,3]
t[1:1]=[7]# 感谢@一往直前 的疑问,之前写为 t[1:1] = 7了
printt# 输出 [1, 7, 2, 3]
这个问题之前还真没遇到过,有谁会对列表这么进行赋值吗?不过对于这个输出结果的原因确实值得去再了解下,毕竟之前也看过《Python源码分析》。(题外话:据说最近有大牛在写新的版本)
想着今天有空看看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;
}
returnlist_ass_slice((PyListObject*)a, ilow, ihigh, v);
}
有用的一句就是 list_ass_slice ,那么再来看看这个函数的代码:
代码如下
staticint
list_ass_slice(PyListObject*a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject*v)
{
/*Because [X]DECREF can recursively invokelistoperations on
thislist, we must postponeall[X]DECREF activity until
after thelistisbackinits canonical shape. Therefore
we must allocate an additional array,'recycle', into which
we temporarily copy the items that are deletedfromthe
list. :-(*/
PyObject*recycle_on_stack[8];
PyObject**recycle=recycle_on_stack;/*will allocate moreifneeded*/
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;/*Changeinsize*/
Py_ssize_t k;
size_t s;
intresult=-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)
returnresult;
result=list_ass_slice(a, ilow, ihigh, v);
Py_DECREF(v);
returnresult;
}
v_as_SF=PySequence_Fast(v,"can only assign an iterable");
if(v_as_SF==NULL)
goto Error;
/*
the5fire注:
要赋值的长度n
*/
n=PySequence_Fast_GET_SIZE(v_as_SF);
vitem=PySequence_Fast_ITEMS(v_as_SF);
}
if(ilow<0)
ilow=0;
elseif(ilow > Py_SIZE(a))
ilow=Py_SIZE(a);
if(ihigh < ilow)
ihigh=ilow;
elseif(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);
returnlist_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;
}
elseif(d >0) {/*Insert d items*/
k=Py_SIZE(a);
if(list_resize(a, k+d)<0)
goto Error;
item=a->ob_item;
printf("关键点\n");
/*
the5fire注:
把list对应切片后一位的值之后的所有内容向后移动所赋值的大小
按照上面的python代码这里就是
原理的t:
|1|2|3|
后移一位,因为len([7])=1
|1|空|2|3|把后两个移位
*/
memmove(&item[ihigh+d], &item[ihigh],
(k-ihigh)*sizeof(PyObject*));
}
/*
the5fire注:
赋值操作,即把[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);
returnresult;
#undef b
}
word; margin: 5px 0px; color: rgb(0, 0, 0);" sans="" font-size:="" font-style:="" font-variant-ligatures:="" font-variant-caps:="" font-weight:="" letter-spacing:="" orphans:="" text-align:="" text-indent:="" text-transform:="" white-space:="" widows:="" word-spacing:="" -webkit-text-stroke-width:="">看了知乎,stackoverflow上的解答,发现源码还是最好的解释。上述关键位置已经加了注释,应该很好理解