Python 元组
上一节学习的列表可以随时增加、删除和修改元素。现在有一个新需求:保存地图坐标、日期信息或固定配置,并避免数据在后续操作中被意外改动,应该选择哪种容器?
元组适合保存这类数据。它和列表一样有顺序,也支持索引和切片;区别在于,元组创建后不能直接修改。
案例:保存固定坐标
需求:保存坐标 (10, 20),后续允许读取,但不允许直接替换其中的数值。
position = (10, 20)
print(position)列表可以修改,元组创建后不能直接修改。
元组创建
除了坐标,城市列表、日期信息和固定配置也可能需要保持不变。元组通常使用 () 创建,元素之间用逗号分隔:
city_tuple = ("长沙", "深圳", "北京")
print(city_tuple)
print(type(city_tuple))运行结果:
('长沙', '深圳', '北京')
<class 'tuple'>也可以使用 tuple() 创建空元组,或者把其他可遍历内容转换成元组:
empty_tuple = tuple()
char_tuple = tuple("Python")
print(empty_tuple)
print(char_tuple)运行结果:
()
('P', 'y', 't', 'h', 'o', 'n')单元素元组
如果固定配置中只有一个值,怎样确保它仍然是元组?元组只有一个元素时,元素后面必须保留逗号:
number_tuple = (1,)
number = (1)
print(number_tuple, type(number_tuple))
print(number, type(number))运行结果:
(1,) <class 'tuple'>
1 <class 'int'>(1) 只是给数字 1 加了一对括号,类型仍然是整数。(1,) 中的逗号才表示这是一个元组。
元组索引、切片与遍历
坐标或固定配置保存下来之后,仍然需要读取其中的某个值、取出一段数据或逐项处理。元组属于序列类型,取值和切片的写法与列表相同。
索引访问
需要读取某个城市或坐标分量时,使用索引按位置取值:
city_tuple = ("长沙", "深圳", "北京")
print(city_tuple[0])
print(city_tuple[-1])运行结果:
长沙
北京元组索引也从 0 开始,-1 表示最后一个元素。索引超出范围时,同样会抛出 IndexError。
切片访问
需要保留一段数据时,使用切片;切片只创建新元组,不会改变原数据:
number_tuple = (0, 1, 2, 3, 4, 5)
print(number_tuple[1:4])
print(number_tuple[:3])
print(number_tuple[::2])
print(number_tuple[::-1])运行结果:
(1, 2, 3)
(0, 1, 2)
(0, 2, 4)
(5, 4, 3, 2, 1, 0)切片会返回一个新元组,不会修改原元组。
元组遍历
需要依次处理所有城市时,使用 for 按顺序取出元组中的每个元素:
city_tuple = ("长沙", "深圳", "北京")
for city in city_tuple:
print(city)元组不可变性
如果有人尝试把坐标中的第一个值改成其他数字,程序会发生什么?元组创建后,不能直接增加、删除或修改其中的元素。
下面的代码会触发错误:
city_tuple = ("长沙", "深圳", "北京")
city_tuple[0] = "上海"运行后会抛出异常:
TypeError: 'tuple' object does not support item assignment元组没有列表中的 append()、insert()、remove() 和 pop() 等修改方法。
如果业务确实需要调整内容,可以先转换成列表,修改后再转回元组:
city_tuple = ("长沙", "深圳", "北京")
city_list = list(city_tuple)
city_list[0] = "上海"
city_tuple = tuple(city_list)
print(city_tuple)运行结果:
('上海', '深圳', '北京')这不是在修改原元组,而是根据修改后的列表创建了一个新元组。
注意
“元组不能修改”指的是不能替换元组直接保存的元素。如果元组中保存了列表,列表内部的内容仍然可以修改:
data = ("课程", ["Python", "MySQL"])
data[1].append("Linux")
print(data)元组查询操作
元组不能修改,是否就不能查询?当然不是。仍然可以获取长度、查找位置、统计次数和判断元素是否存在:
| 操作 | 作用 |
|---|---|
len(tuple_data) | 获取元素数量 |
tuple_data.index(data) | 查询元素第一次出现的索引 |
tuple_data.count(data) | 统计元素出现的次数 |
data in tuple_data | 判断元素是否存在 |
score_tuple = (90, 85, 90, 100)
print(len(score_tuple))
print(score_tuple.index(85))
print(score_tuple.count(90))
print(100 in score_tuple)运行结果:
4
1
2
True列表与元组的选择
遇到一组数据时,关键问题是“后续是否允许修改”。列表和元组都能按顺序保存多个数据,但适用场景不同:
| 对比项 | 列表 list | 元组 tuple |
|---|---|---|
| 常用写法 | [1, 2, 3] | (1, 2, 3) |
| 是否有顺序 | 是 | 是 |
| 是否支持索引、切片 | 是 | 是 |
| 是否可以修改 | 可以 | 不可以 |
| 常见场景 | 内容需要增删改 | 内容创建后保持不变 |
可以按下面的需求选择:
- 学生名单后续还会增加或删除,使用列表
- 地图坐标创建后不应该变化,使用元组
元组通常占用更少的内存,遍历速度也可能略快。但选择元组的首要原因不是性能,而是明确表达“这组数据不应该修改”。
只包含数字、字符串等不可变数据的元组,可以作为字典的键或集合的元素。如果元组中包含列表,就不能这样使用。字典和集合会在后面的章节学习。
小结
本节先回答四个问题:
- 什么数据适合用元组?有顺序且创建后不应修改的数据
- 如何读取元组?使用索引、切片和
for遍历 - 单元素元组如何表示?元素后必须保留逗号
- 元组需要调整时怎么办?转换为列表修改,再创建新元组;如果数据本来就要增删改,应直接使用列表
练习
- 创建一个包含 3 个城市名称的元组
- 取出第一个元素、最后一个元素和前两个元素
- 使用
for遍历并打印所有城市 - 尝试修改其中一个元素,观察
TypeError