编程学习网 > 编程语言 > Python > Python 的 list 与 tuple 底层实现区别?
2025
08-20

Python 的 list 与 tuple 底层实现区别?


很多同学在准备 Python 面试的时候,总会被问到一个看似简单但其实挺有门道的问题:list 和 tuple 到底有什么区别?表面上看,一个能改,一个不能改,好像就这么点事儿。但真要往底层刨,就会发现里面的差异可不只是“可变和不可变”这么轻描淡写。

先从日常用法说起。list 是我们平时用得最多的数据结构,支持增删改查,随便 append、pop、insert,简直就像家里的杂物箱,啥都能往里扔。而 tuple 呢,看起来像是“轻量版的 list”,一旦建好了就动不了,经常被用来当字典的 key,或者函数的返回值。光从语法层面看,好像 tuple 只是加了个“不能改”的限制。但这只是表象,底层实现其实差别蛮大的。

Python 里,list 的底层是一种动态数组。什么意思呢?当你新建一个 list,Python 会在内存里开一块区域,用来存储元素的引用。注意,是引用,不是对象本身。比如你写 [1, 2, 3],list 里放的并不是整数 1、2、3,而是指向这些整数对象的指针。这么做的好处是,list 可以存放不同类型的元素,而且扩容的时候只要拷贝指针就行,速度会快很多。

动态数组还有个特性,就是它会“预分配”空间。你往 list 里 append 元素的时候,如果当前容量不够了,Python 会重新申请一块更大的内存,把旧的元素搬过去,再加上新的。这就解释了为啥 list 在尾部追加元素的摊销复杂度是 O(1),但偶尔会突然慢一下——那就是触发了扩容。扩容策略在 CPython 里是指数级增长的,避免你每次加一个元素都要重新分配内存。

tuple 就完全不同了。tuple 的大小在创建时就固定下来了,所以它不会像 list 那样有个“预留空间”。Python 在分配 tuple 的时候,直接开辟一块正好能装下所有元素引用的内存,就这么多,不多也不少。这也就是为什么 tuple 相对更轻量,它不需要考虑扩容,不需要维护额外的容量信息,内存布局更紧凑。

说到这,你可能会想,那 tuple 只是 list 的一个“阉割版”,是不是没啥用?其实恰恰相反,因为 tuple 的不可变性,它才能作为字典的 key,或者放进 set 里。你想想,如果 key 能随便变,哈希表还能正常工作吗?而且 tuple 的不可变在多线程环境下也更安全,不会有“边读边写”的坑。

再往细里说,list 和 tuple 的对象头部结构也不一样。在 CPython 里,每个对象都有 PyObject 的基本信息,比如引用计数和类型指针。list 的结构里还额外带了分配容量(allocated)的字段,用来记录当前这块内存能放多少元素。而 tuple 则直接存储长度,没有“额外冗余”。这点在 CPython 的源码里能看得很清楚。

举个例子,list 的 C 结构大概是这样的(简化过的伪代码):

而 tuple 就精简很多:

看出来了吧?list 有个 allocated 字段专门记容量,tuple 没有,所以 tuple 在存储上更紧凑,访问速度理论上也会快一点。

那问题来了,实际用的时候,性能差别大吗?我的经验是,如果只是做普通的数据存储,这点差别几乎感知不到。但在一些对性能敏感的场景,比如作为函数返回多个值,或者当作 dict 的 key 时,tuple 就显得特别合适。因为它既节省内存,又保证了不变性,不会出现奇奇怪怪的 bug。

另外,很多人忽视的一点是,tuple 的不可变性只是“浅不可变”。什么意思?就是 tuple 自己的结构不能变,但里面的元素如果是可变对象,那还是能改的。比如 ( [1,2], 3 ) 这个 tuple,本身不能 append 新元素,但里面那个 list 还是能改。这在写代码的时候要格外小心,不然你以为是安全的结果,其实里面的值被人悄悄改了。

回到面试的语境,面试官问 list 和 tuple 的底层区别,如果你只回答“list 可变,tuple 不可变”,那基本就凉了。他真正想考察的是你对 Python 内存模型和对象实现的理解。能聊到 list 的动态数组、扩容机制,tuple 的紧凑存储和不可变性,甚至能扯到 CPython 的源码结构,那肯定是加分项。

我自己平时写代码的时候,选择 list 还是 tuple,有几个经验法则:需要频繁改动、追加、删除的,用 list;需要保证稳定、不被修改,尤其是要做 key 的,用 tuple。别觉得 tuple 没啥用,它在做数据结构的“胶水”时特别合适。比如我们经常写的 graph 节点 (u, v),要存进一个 set 里去重,那只能用 tuple,list 就不行。

说实话,Python 的这些小细节,刚学的时候真容易被忽视。大家都忙着刷题、写业务代码,根本没空去翻源码。但如果你真想在面试里脱颖而出,或者以后往更底层的方向走,这些东西都是必须懂的。理解 list 和 tuple 的实现差别,其实就是打开了 Python 内部世界的一扇门。你会发现,所谓的“高级语言”,底下还是那点 C 语言的刀耕火种,只是帮你包了一层皮。

最后我想抛个问题给你们:既然 tuple 更轻量,那为什么 Python 不干脆只用 tuple,把所有地方都搞成不可变的,再用别的方式提供修改呢?其实这就是设计权衡的问题了。list 提供的灵活性,在很多场景下是必不可少的。你要是每次都创建新对象去模拟修改,性能早就崩了。所以别想着非此即彼,两者各有定位,学会选才是真本事。

以上就是“Python 的 list 与 tuple 底层实现区别?的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取