元组就是不能修改的列表
元组和列表乍看很像:都是有序序列,都支持索引和遍历。但有一个关键区别改变了一切:元组是不可变的。元组一旦创建,就不能往里添加、从中删除,也不能替换其中的元素。
元组用圆括号来写(有时也可以不写括号):
只有一个元素的元组需要在末尾加逗号,否则 Python 会把圆括号当作普通的分组括号:
空元组则写成 ():
不可变性的实际表现
试图修改元组,Python 会阻止你:
你可以随意读取元组:索引、切片、遍历、in 都没问题,只是不能修改它。需要一个不同的元组时,就新建一个。
为什么要用一个不能修改的东西?
不可变听起来像是限制,但它往往正是你需要的特性。
- 安全。 把元组传进函数,它不会在你不知情的情况下被修改。
- 可哈希。 由不可变值组成的元组可以用作字典的键或集合的元素,列表不行。
- 表达意图。 元组表示“这是一条结构固定的记录”。
point = (3, 4)比point = [3, 4]更清楚地表达了“两个坐标”。
元组特别适合这些场景:
- 坐标:
(x, y)、(lat, lon) - RGB 颜色:
(255, 128, 0) - 记录:
(name, email, signup_date) - 从函数返回多个值
解包
元组和解包语法简直是天生一对:
真正完成解包的是左边的逗号。Python 看到两个名字和一个有两个值的元组,就把它们一一对应地绑定起来。
地道的 Python 代码里到处都是这种写法:
你可以用 * 收集“剩下的部分”:
只关心第一个和最后一个元素时,这招很方便。
用元组作字典的键
元组是可哈希的(只要它的内容也可哈希),所以可以用作字典的键。列表做不到:
这种用多个值组合成一个键的写法出奇地好用。比如“用户 X 在第 Y 天的分数”,或者“从 A 到 B 的最佳路线”。
用元组返回多个值
需要返回多个结果的函数,通常返回一个元组:
Python 内置的 divmod() 正是这么做的。调用方用解构赋值接收结果,读起来很自然。
当位置不够用时:命名元组
元组一旦超过两三个元素,记住哪个位置代表什么就变得很麻烦。collections.namedtuple 解决了这个问题:
现在元组的每个元素都有了名字。它仍然不可变,仍然是元组(所以解包和索引照样能用),但访问方式友好多了。更复杂的情况可以用 dataclasses,我们会在后面的类一章中介绍。
元组还是列表:快速决策指南
- 结构固定,每个位置都有含义 → 元组。
- 集合可能变大或变小 → 列表。
- 从函数返回多个值 → 元组。
- 需要用作字典的键或集合的元素 → 元组(列表不行)。
- 之后要修改它 → 列表(元组不允许)。
继续学习
元组覆盖的是一端:固定、小巧、有结构。接下来是集合,它负责完全不同的工作:快速判断成员是否存在,以及保证元素唯一。
常见问题
Python 中的元组是什么?
元组是有序且不可变的序列:和列表很像,但一旦创建,就不能增加、删除或修改其中的元素。元组用圆括号来写:point = (3, 4)。
元组和列表有什么区别?
两者都是有序序列。列表是可变的,创建后还能修改;元组是不可变的。元组通常用来存放少量本该放在一起的值,作为一条“记录”,比如坐标,或者函数返回的多个值。
什么时候应该用元组?
当你有一条大小固定、每个位置都有特定含义的记录时,就用元组:坐标、RGB 颜色、数据库中的一行。另外,要把一组值当作字典的键或集合的元素时也用元组,因为列表不能这样用。其他集合可能变大或变小的情况,默认用列表。