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

发布时间 - 2026-01-11 01:01:04    点击率:

本文主要介绍的关于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切片  # python列表的切片赋值实现  # 解下  # 的是  # 很好  # 看了  # 相关内容  # 去了  # 最好的  # 一句  # 中有  # 这个问题  # 再来  # 会对  # 问了  # 这篇文章  # 有谁  # 谢谢大家  # 所有内容  # 遇到过  # 大牛  # 即把 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)  如何在宝塔面板中创建新站点?  如何在建站之星网店版论坛获取技术支持?  Win11怎么设置默认图片查看器_Windows11照片应用关联设置  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】  Laravel如何处理和验证JSON类型的数据库字段  如何挑选高效建站主机与优质域名?  如何在香港免费服务器上快速搭建网站?  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  如何快速搭建高效WAP手机网站吸引移动用户?  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  如何获取上海专业网站定制建站电话?  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  JavaScript如何实现倒计时_时间函数如何精确控制  Laravel怎么清理缓存_Laravel optimize clear命令详解  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音  微信小程序 闭包写法详细介绍  如何快速搭建安全的FTP站点?  如何在阿里云购买域名并搭建网站?  网站建设保证美观性,需要考虑的几点问题!  Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  Bootstrap整体框架之CSS12栅格系统  如何在阿里云ECS服务器部署织梦CMS网站?  敲碗10年!Mac系列传将迎来「触控与联网」双革新  Laravel如何处理表单验证?(Requests代码示例)  ,交易猫的商品怎么发布到网站上去?  HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】  Java垃圾回收器的方法和原理总结  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)  Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置  javascript读取文本节点方法小结  javascript如何操作浏览器历史记录_怎样实现无刷新导航  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作  Laravel如何将应用部署到生产服务器_Laravel生产环境部署流程  如何在阿里云域名上完成建站全流程?  Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  Python文件异常处理策略_健壮性说明【指导】  米侠浏览器网页背景异常怎么办 米侠显示修复  lovemo网页版地址 lovemo官网手机登录  高防服务器租用指南:配置选择与快速部署攻略  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  Win11关机界面怎么改_Win11自定义关机画面设置【工具】  太平洋网站制作公司,网络用语太平洋是什么意思?