Python 常用数据结构之元组详解
在 Python 中,列表是一种常用的容器型数据类型,用于保存多个数据并通过循环实现批量操作。除了列表之外,Python 还提供另一种重要的容器型数据类型——元组(tuple)。元组与列表类似,都是有序序列,但在可变性上存在本质区别。
Python 元组是不可变序列类型,用于存储有序数据。相比列表,元组一旦创建无法修改元素,适合多线程环境且创建效率更高。本文介绍了元组的定义语法、索引切片、拼接成员运算、打包解包操作及变量交换技巧,探讨了元组作为字典键和函数返回值的应用场景,并通过 timeit 模块对比了元组与列表的创建性能差异,最后总结了两者在可变性及适用场景上的区别。

在 Python 中,列表是一种常用的容器型数据类型,用于保存多个数据并通过循环实现批量操作。除了列表之外,Python 还提供另一种重要的容器型数据类型——元组(tuple)。元组与列表类似,都是有序序列,但在可变性上存在本质区别。
在 Python 中,元组是由多个元素按照一定顺序构成的序列。元组是不可变类型,这意味着一旦定义,其中的元素不能添加、删除或修改。如果试图修改元组中的元素,将引发 TypeError 错误。
定义元组通常使用形如 (x, y, z) 的字面量语法。元组支持的运算符与列表基本一致。
# 定义一个三元组
t1 = (35, 12, 98)
# 定义一个四元组
t2 = ('骆昊', 43, True, '四川成都')
# 查看变量的类型
print(type(t1)) # <class 'tuple'>
print(type(t2)) # <class 'tuple'>
# 查看元组中元素的数量
print(len(t1)) # 3
print(len(t2)) # 4
元组支持索引运算和切片运算,用法与列表相同。
# 索引运算
print(t1[0]) # 35
print(t1[2]) # 98
print(t2[-1]) # 四川成都
# 切片运算
print(t2[:2]) # ('骆昊', 43)
print(t2[::3]) # ('骆昊', '四川成都')
可以通过循环遍历元组中的元素,也可以使用 in 和 not in 进行成员判断。
# 循环遍历元组中的元素
for elem in t1:
print(elem)
# 成员运算
print(12 in t1) # True
print(99 in t1) # False
print('Hao' not in t2) # False
元组支持拼接运算(+)和比较运算(==, >=, <= 等)。
# 拼接运算
t3 = t1 + t2
print(t3) # (35, 12, 98, '骆昊', 43, True, '四川成都')
# 比较运算
print(t1 == t3) # False
print(t1 >= t3) # False
print(t1 <= (35, 11, 99)) # False
() 表示空元组。() 仅作为改变运算优先级的圆括号。
('hello', ) 和 (100, ) 是一元组。('hello') 和 (100) 只是字符串和整数。a = ()
print(type(a)) # <class 'tuple'>
b = ('hello')
print(type(b)) # <class 'str'>
c = (100)
print(type(c)) # <class 'int'>
d = ('hello', )
print(type(d)) # <class 'tuple'>
e = (100, )
print(type(e)) # <class 'tuple'>
当把多个用逗号分隔的值赋给一个变量时,多个值会自动打包成一个元组。
# 打包操作
a = 1, 10, 100
print(type(a)) # <class 'tuple'>
print(a) # (1, 10, 100)
将一个元组赋值给多个变量时,元组会解包成多个值分别赋给对应的变量。如果元素个数与变量个数不对应,会引发 ValueError 异常。
# 解包操作
i, j, k = a
print(i, j, k) # 1 10 100
# 错误示例:值太多
# i, j, k = a # ValueError: too many values to unpack (expected 3)
# 错误示例:值不足
# i, j, k, l, m, n = a # ValueError: not enough values to unpack (expected 6, got 3)
为了解决变量个数少于元素个数的问题,可以使用星号表达式(*)。被星号修饰的变量会接收剩余的所有值并转换为列表。注意,星号表达式在解包语法中只能出现一次。
a = 1, 10, 100, 1000
i, j, *k = a
print(i, j, k) # 1 10 [100, 1000]
i, *j, k = a
print(i, j, k) # 1 [10, 100] 1000
*i, j, k = a
print(i, j, k) # [1, 10] 100 1000
解包语法适用于所有序列,包括列表、range 对象甚至字符串。
a, b, *c = range(1, 10)
print(a, b, c) # 1 2 [3, 4, 5, 6, 7, 8, 9]
a, b, c = [1, 10, 100]
print(a, b, c) # 1 10 100
a, *b, c = 'hello'
print(a, b, c) # h ['e', 'l', 'l'] o
在 Python 中,交换两个或多个变量的值非常便捷,无需中间变量。
# 交换两个变量
a, b = b, a
# 交换三个变量
a, b, c = b, c, a
底层机制涉及打包和解包,对于多于三个变量的互换,需要通过打包解包方式完成。
既然有了列表,为什么还需要元组?主要原因如下:
使用 timeit 模块可以测试创建相同元素数量的列表和元组的时间差异。
import timeit
print('%.3f 秒' % timeit.timeit('[1, 2, 3, 4, 5, 6, 7, 8, 9]', number=10000000))
print('%.3f 秒' % timeit.timeit('(1, 2, 3, 4, 5, 6, 7, 8, 9)', number=10000000))
通常情况下,创建元组的速度显著快于列表。
元组和列表可以相互转换。
infos = ('骆昊', 43, True, '四川成都')
# 将元组转换成列表
print(list(infos)) # ['骆昊', 43, True, '四川成都']
frts = ['apple', 'banana', 'orange']
# 将列表转换成元组
print(tuple(frts)) # ('apple', 'banana', 'orange')
由于元组是不可变的,它可以作为字典的键(Key),而列表因为可变不能作为键。
scores = {
('Alice', 'Math'): 95,
('Bob', 'Math'): 88,
}
print(scores[('Alice', 'Math')]) # 95
Python 函数默认返回单个值,但通过元组打包,可以方便地返回多个结果。
def get_min_max(numbers):
return min(numbers), max(numbers)
result = get_min_max([1, 5, 3, 9, 2])
print(result) # (1, 9)
列表和元组都是容器型的数据类型,即一个变量可以保存多个数据,而且它们都是按一定顺序组织元素的有序容器。
在实际开发中,如果数据不需要修改,优先使用元组可以提高程序的安全性和运行效率;如果需要频繁修改数据集合,则使用列表。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online