Python列表list底层源码实现及解析

本文使用的图均来自up:凸头统治地球
小伙伴们如果看完文章有什么不懂的地方,可以观看原视频讲解:python列表底层原理剖析(基于c源码学python list 内部实现)

1.创建list

Python底层是用C写的,因此列表在底层相当结构体变量,主要源码如下所示(实际上会有很多东西,后续的源码同理)。
在这里插入图片描述
前面之所以有两个指针,是因为一个list对象相当于双向链表中的一个节点,需要前指针和后指针进行相连。

下面是创建list的源码,注意返回值是一个指针,这意味着我们定义一个列表a = [],a中实际存的是一个地址,该地址指向列表中的元素。

在这里插入图片描述

2.添加元素append()

下图描述了给列表添加元素的大概过程。当我们调用append方法时,首先会在内存中创建一个空间,里面存着需要添加进列表的元素对象,之后才将该内存的地址放进列表所指向空间中(所以用来存放列表元素的是一个双指针**ob_item)。由于我们创建一个列表时,allocated实际上是等于0的,即列表的容量是0。当需要往列表append元素后,首先会判断容量够不够,够的话加就直接将添加元素的内存地址存进去,不够就扩容,按照0, 4, 8, 16 ,24的成长线进行扩容。
在这里插入图片描述
扩容细节
1)首先判断列表的空间是否足够,如果空间太大,就缩容,不够才扩容。
在这里插入图片描述
2)开辟内存中如果存在连续的空间,就不需要迁移,如果不存在,就需要将列表中原来的元素进行迁移,与新元素进行合并。

在这里插入图片描述

3.插入元素insert

插入元素需要将前面所有元素往前移动,同时计算内存空间是否充足,下图就是插入元素的一个流程。明显可以看出Insert时间复杂度为O(n),而append时间复杂度为O(1)。同理pop(0)时间复杂度为O(n),pop时间复杂度为O(1),如果需要进行insert和pop(0)可以使用双端队列deque,上面两种操作时间复杂度都为O(1)。
在这里插入图片描述
insert()函数源码如下:
在这里插入图片描述

4.移除元素pop

移除元素是直接将把需要移除对象的引用计数减一,并将列表的size减一。列表所指向的内存空间实际未发生任何改变的。之所以这样,是因为当我们需要添加元素时,是根据obj_size的值来确定添加位置,因此只要将新元素地址直接覆盖已删除元素地址就行,这样不仅能实现功能,还能减少删除操作,提高性能。
在这里插入图片描述
pop()源码如下:
在这里插入图片描述

5.清空列表clear

这块没什么说的,就是将list结构体中相关变量的值重置为零,流程如下:
在这里插入图片描述
clear()源码如下,注意标红的while循环,清空操作虽然将相关变量都重置为0,但需要通过这个while循环将列表所有对象的引用计数都减一,以对应垃圾回收机制。
在这里插入图片描述

6.销毁列表del

销毁一个列表对象时,会执行如下操作:
首先,将列表的引用计数器-1,此时:

1)如果引用计数器>0,表示还有其他变量使用此列表,之后不做任何操作。

2)如果引用计数器=0,表示没人使用此列表,之后需要做如下事宜。

  • 如果列表中有数据,则先处理元素,其实就是找到每个元素,将元素的引用计数器-1(如果元素的引用计数器为O,则元素可以被GC回收)
  • 处理完元素后,ob_item=NULL 、ob_size=0 、ob_allocated=0
  • 将列表从管理内存的双向环状链表中移除,认为这个对象没人使用了,现在可以被销毁了。
  • Python为了提高列表的效率,在内部设置了free_list ,它可以缓存80个列表,当有些列表没人使用后不会立即销毁,而是放在 free list中,以便再创建列表对象时可以直接从缓存中拿到列表的结构体对象并重新初始化,然后再来使用。如果free_list中已缓存了80个了,那么再有列表被销毁时,就会直接在内存中将对象销毁。下图就是对free_list 的一个验证,先删除列表,再创建列表,新建的列表和删除的列表地址相同。
    在这里插入图片描述
    del()源码如下:
    在这里插入图片描述
  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值