list是python的高级特性,今天我们来学习一下list的底层结构。list(列表)就像一个大仓库,里边什么都可以放,学习过底层结构之后,就会认同这句话。python中一切皆对象,先点出来,列表中存放的元素其实是泛型指针PyObject*,所以什么都可以放。根据我们列表的直观感受,每个列表中的元素个数可能会不一样,所以列表示一个变长对象;列表中的元素可以进行添加、删除、修改等操作,所以列表是一个可变对象。

列表常用的操作

其中,需要注意的是性能问题,pop从尾部弹出一个元素,时间复杂度为O(1);从头部弹出一个元素,后面的元素都需要移动,时间复杂度为O(n)。

先看一下List 对象的底层结构,PyListObject,通过前面的学习,这个很简单了。

typedef struct {    PyObject_VAR_HEAD//变长对象公共头部信息    PyObject **ob_item;//二级指针,指向一个PyObject*类型的指针数组,     //这个指针数组保存的是对象指针    Py_ssize_t allocated;//列表底层使用C数组,列表的容量,非实际大小} PyListObject;

通过前面的学习,我们知道一个变长对象是通过ob_size字段来指示对象的实际大小的。列表多了一个字段allocated来表示容量,之所以要有容量这个概念,是因为列表需要动态添加元素。在动态添加元素时,如果每添加一个元素,就申请一次数组,将所有元素都拷贝一次,性能太低。加了容量这个字段,添加新元素,发现底层数组已满,会将底层数组申请的长一些,添加元素的时候不用每次都申请新的数组。

PyListObject示意图

可以看出,此时列表中有两个元素,但是列表的容量是6。我们再append两个元素,如下示意图,可以看出容量最大为6,不需要重新申请数组。

尾部添加元素示意图

在此基础上再增加三个元素在尾部,实际元素个数为7,容量为6,需要扩容,看一下示意图:原来的容量为6,元素个数为4,append3个元素后,假设容量为10,元素个数为7。扩容的时候把容量申请的比实际元素大一些。然后将原来数组中的PyObject*按照顺序依次拷贝到新的数组里边,再将ob_item指向新的数组,再将ob_size加3。这就是列表扩容的过程。看一下实际源码

list对象扩容底层示意图

//代码位置cpython-masterObjectslistobject.clist_resize(PyListObject *self, Py_ssize_t newsize)//参数self就是列表,newsize是元素添加或者减少之后的ob_size{    PyObject **items;//这个二级指针,用来指向指针数组    size_t new_allocated, num_allocated_bytes;//新的容量和对应的内存大小    Py_ssize_t allocated = self->allocated;//获取原来的容量  //如果newsize达到了总量的一半,但是还没有超过容量,说明newsize和容量的匹配的,不会扩容    if (allocated >= newsize && newsize >= (allocated >> 1)) {        assert(self->ob_item != NULL || newsize == 0);        Py_SET_SIZE(self, newsize);        return 0;    }//走到这里说明容量和ob_size不匹配,要进行扩容或者缩容  //新申请的底层数组的容量由下边的公式决定    new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; //也不能过度分配    if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize))        new_allocated = ((size_t)newsize + 3) & ~(size_t)3;  //如果newsize为0,那么容量也会清空    if (newsize == 0)        new_allocated = 0;   //数组中存放的是PyObject*,所以要计算内存    num_allocated_bytes = new_allocated * sizeof(PyObject *);    //申请相应大小的内存,赋值给指针items    items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes);  //申请失败    if (items == NULL) {        PyErr_NoMemory();        return -1;    }  //指向新的数组,实现扩容或者缩容    self->ob_item = items;  //元素的实际个数    Py_SET_SIZE(self, newsize);  //原来容量的大小设置为新的大小    self->allocated = new_allocated;    return 0;}

new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3;

从这个公式的注释得到扩容的规律:The growth pattern is: 0, 4, 8, 16, 24, 32, 40, 52, 64, 76, ...

c++ list 修改_Cpython源码阅读17-list自动扩容原理相关推荐

  1. pytorch load state dict_pytorch源码阅读(二)optimizer原理

    pytorch包含多种优化算法用于网络参数的更新,比如常用的SGD.Adam.LBFGS以及RMSProp等.使用中可以发现各种优化算法的使用方式几乎相同,是因为父类optimizer[1]定义了各个 ...

  2. 【Spring Boot实战】源码解析Spring Boot自动配置原理

    一.简介 Spring致力于让Java开发更简单,SpringBoot致力于让使用Spring进行Java开发更简单,SpringCloud致力于基于SpringBoot构建微服务生态圈,让微服务开发 ...

  3. 17 任务调度相关类综述——Live555源码阅读(一)任务调度相关类

    这是Live555源码阅读的第二部分,包括了任务调度相关的三个类.任务调度是Live555源码中很重要的部分. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/ol ...

  4. spring源码阅读(3)-- 容器启动之BeanFactoryPostProcessor

    接着上文<spring源码阅读(2)-- 容器启动之加载BeanDefinition>,当spring加载完所有BeanDefinition时,并不会马上去创建bean,而是先配置bean ...

  5. NJ4X源码阅读分析笔记系列(三)—— nj4x-ts深入分析

    NJ4X源码阅读分析笔记系列(三)-- nj4x-ts深入分析 一.系统的工作流程图(模块级) 其工作流程如下(以行情获取为例): 应用端向Application Server发起连接 应用服务器调用 ...

  6. gh-ost大表DDL工具源码阅读

    gh-ost大表DDL工具源码阅读 最终目的 开发环境与测试数据库准备 一个简单的ddl案例 debug分析程序执行过程 vscode debug配置 变量介绍 核心处理逻辑 分析我的需求 最终目的 ...

  7. Golang流媒体实战之五:lal推流服务源码阅读

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos <Golang流媒体实战>系列的链接 体验 ...

  8. Mybatis 源码阅读环境搭建

    Mybatis源码阅读环境搭建 前言 一.下载mybatis的源码 二.编译源码 三.创建测试项目 前言     mybatis源码阅读环境搭建还是比较简单的,接下来我们讲解一下如何搭建该源码阅读环境 ...

  9. Spark源码学习之IDEA源码阅读环境搭建

    软件准备 (1)Java 1.8 (2)Scala 2.11.12(需要在IDEA中安装) (3)Maven 3.8.2(需要在IDEA中配置) (4)Git 2.33 以上软件需要安装好,并进行环境 ...

最新文章

  1. js 获取input type=file 文件,并且上传
  2. 人生第一次:领年终,拿股票!
  3. [转]40种网页常用小技巧----Ajax中国
  4. typora最好用的主题_谁是我心中最好的写作工具?
  5. 计算机里的文件弄不到桌面怎么办,笔记本电脑桌面上的文件夹不见了怎么办
  6. android构建过程
  7. 《网络安全——应用技术与工程实践》
  8. leetcode - Missing Ranges
  9. android 应用退到后台,类似最小化
  10. CRM One Order search max hit实现原理讨论
  11. stdin,stdout,stderr
  12. HTML5与HTML4区别
  13. vpp之node节点分析二: qs类型
  14. 微型计算机原理王忠民PPT,微型计算机原理4 王忠民著.ppt
  15. DX11 游戏开发笔记 (一) 资源介绍
  16. ios 图表_在ios应用中实现蜘蛛网图表
  17. 青春魅族为何一幅“龙钟老态”?
  18. 使用CDN后网页无法访问怎么解决
  19. 论文阅读利器——划词翻译插件(桌面与浏览器)
  20. jquery 学习笔记及小练习

热门文章

  1. MySql数据库连接池
  2. 体验XHProf(linux版本)
  3. Bug反思:减少笔误
  4. dubbo web工程示例_带有Dubbo的Spring Cloud Alibaba
  5. java中自造类是什么意思_JAVA问题,什么时候需要,Class类型的?
  6. tcpip c语言程序设计,TCP 服务端和客户端程序设计(C)
  7. android 微信登录点击没翻译,[android] 微信登录,没有唤起微信,直接返回ERR_AUTH_DENIED...
  8. c语言基础傅里叶变换,急求:C语言如何实现快速傅里叶变换
  9. 【Nginx】截取URL中某个参数Parameter
  10. MySQL 错误 #1113