通过源码分析Python中的切片赋值


Posted in Python onMay 08, 2017

本文主要介绍的关于Python切片赋值的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:

昨天有同学问了我这么个问题:

t = [1, 2, 3]
t[1:1] = [7] # 感谢@一往直前 的疑问,之前写为 t[1:1] = 7了
print t # 输出 [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;
 }
 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;
  /*
  the5fire注:
  要赋值的长度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");
  /*
  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);
 return result;
#undef b
}

看了知乎,stackoverflow上的解答,发现源码还是最好的解释。上述关键位置已经加了注释,应该很好理解。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python 参数列表中的self 显式不等于冗余
Dec 01 Python
Python中让MySQL查询结果返回字典类型的方法
Aug 22 Python
python获取android设备的GPS信息脚本分享
Mar 06 Python
浅谈Python单向链表的实现
Dec 24 Python
浅谈Python 中整型对象的存储问题
May 16 Python
Python字符串处理实例详解
May 18 Python
python机器学习之神经网络(二)
Dec 20 Python
解决python有时候import不了当前的包问题
Aug 28 Python
python进程间通信Queue工作过程详解
Nov 01 Python
基于python实现上传文件到OSS代码实例
May 09 Python
在pycharm中无法import所安装的库解决方案
May 31 Python
Python排序算法之插入排序及其优化方案详解
Jun 11 Python
Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)
May 08 #Python
Python实现Windows和Linux之间互相传输文件(文件夹)的方法
May 08 #Python
Python实现SSH远程登陆,并执行命令的方法(分享)
May 08 #Python
利用Celery实现Django博客PV统计功能详解
May 08 #Python
浅谈Python生成器generator之next和send的运行流程(详解)
May 08 #Python
python生成式的send()方法(详解)
May 08 #Python
python实时分析日志的一个小脚本分享
May 07 #Python
You might like
德生H-501的评价与改造
2021/03/02 无线电
PHP调用VC编写的COM组件实例
2014/03/29 PHP
JQuery一种取同级值的方式(比如你在GridView中)
2012/03/15 Javascript
jQuery中RadioButtonList的功能及用法实例介绍
2013/08/23 Javascript
js中substring和substr的详细介绍与用法
2013/08/29 Javascript
jQuery的3种请求方式$.post,$.get,$.getJSON
2014/03/28 Javascript
nodejs 实现模拟form表单上传文件
2014/07/14 NodeJs
js实现简单鼠标跟随效果的方法
2015/04/10 Javascript
js获取及修改网页背景色和字体色的方法
2015/12/29 Javascript
老生常谈 js中this的指向
2016/06/30 Javascript
JQuery实现DIV其他动画效果的简单实例
2016/09/18 Javascript
关于JS Lodop打印插件打印Bootstrap样式错乱问题的解决方案
2016/12/23 Javascript
基于Javascript实现的不重复ID的生成器
2016/12/25 Javascript
vue.js 微信支付前端代码分享
2018/02/10 Javascript
使用vue实现通过变量动态拼接url
2020/07/22 Javascript
解析Mac OS下部署Pyhton的Django框架项目的过程
2016/05/03 Python
解决python3爬虫无法显示中文的问题
2018/04/12 Python
django表单实现下拉框的示例讲解
2018/05/29 Python
浅谈Python中的可迭代对象、迭代器、For循环工作机制、生成器
2019/03/11 Python
python实现udp聊天窗口
2020/03/31 Python
详解CSS3选择器:nth-child和:nth-of-type之间的差异
2017/09/18 HTML / CSS
CSS3实现菜单悬停效果
2020/11/17 HTML / CSS
Crucial英睿达法国官网:内存条及SSD固态硬盘升级
2018/07/13 全球购物
数控技术与应用毕业生自荐信
2013/09/24 职场文书
大学毕业感言50字
2014/02/07 职场文书
团委书记的竞聘演讲稿
2014/04/24 职场文书
工程售后服务承诺书
2014/05/21 职场文书
完美的中文自荐信
2014/05/24 职场文书
环卫工人节活动总结
2014/08/29 职场文书
学习朴航瑛老师爱岗敬业先进事迹思想汇报
2014/09/17 职场文书
2014员工聘用协议书(最新版)
2014/11/24 职场文书
小学生通知书评语
2014/12/31 职场文书
委托书格式要求
2015/01/28 职场文书
2016年五四青年节校园广播稿
2015/12/17 职场文书
2016年全国爱眼日宣传教育活动总结
2016/04/05 职场文书
Go中的条件语句Switch示例详解
2021/08/23 Golang