通过源码怎么去分析python|通过源码怎么去分析Python中的切片赋值

更新时间:2021-07-01    来源:python    手机版     字体:

【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

}

 

本文来源:http://www.bbyears.com/jiaocheng/127105.html

热门标签

更多>>

本类排行