一、什么是元组?
元组(tuple) 是 Python 中一种内置的有序序列,与列表非常相似,但有一个关键区别:元组是不可变的,即一旦创建,就不能修改、添加或删除其中的元素。
# 元组示例point = (10, 20)colors = ("红", "绿", "蓝")person = ("张三", 25, "北京")
二、元组的创建
2.1 使用圆括号 ()
最常见的方式是用圆括号括起元素,元素之间用逗号分隔。
# 空元组empty_tuple = ()# 多个元素的元组t1 = (1, 2, 3)t2 = ("苹果", "香蕉", "橙子")t3 = (1, "hello", 3.14, True) # 混合类型
2.2 使用 tuple() 构造函数
tuple() 函数可以将其他可迭代对象(如列表、字符串、range等)转换为元组。
# 从列表转换list_data = [1, 2, 3]t = tuple(list_data) # (1, 2, 3)# 从字符串转换s = "hello"t = tuple(s) # ('h', 'e', 'l', 'l', 'o')# 从 range 转换t = tuple(range(5)) # (0, 1, 2, 3, 4)# 不传参数创建空元组t = tuple() # ()
2.3 单个元素的元组(逗号是关键)
创建只有一个元素的元组时,必须在元素后面加上逗号,否则圆括号会被解释为数学运算中的括号。
# ❌ 错误:这是整数 5,不是元组not_tuple = (5)print(type(not_tuple)) # <class 'int'># ✅ 正确:单个元素元组single_tuple = (5,)print(single_tuple) # (5,)print(type(single_tuple)) # <class 'tuple'>
2.4 无括号的元组——逗号分隔即可
在不引起歧义的情况下,可以省略圆括号,直接用逗号分隔元素。这称为“元组打包”。
t = 1, 2, 3# 等价于 (1, 2, 3)print(t) # (1, 2, 3)print(type(t)) # <class 'tuple'># 函数返回多个值时,实际上返回的就是一个元组defget_point():return10, 20# 返回 (10, 20)
2.5 嵌套元组
元组中的元素可以是任何类型,包括元组本身,从而形成嵌套结构。
nested = ((1, 2), (3, 4), (5, 6))print(nested[1]) # (3, 4)print(nested[1][0]) # 3
三、元组的特性
3.1 有序性
元组中的元素按照定义的顺序存储,每个元素都有固定的位置(索引)。可以通过索引访问。
t = (10, 20, 30, 40)print(t[0]) # 10print(t[-1]) # 40(负数索引从末尾开始)
3.2 不可变性
元组一旦创建,其元素的值和顺序都不能改变。这意味着不能对元组进行修改、添加或删除操作。
t = (1, 2, 3)# t[1] = 20 # TypeError: 'tuple' object does not support item assignment# t.append(4) # AttributeError: 'tuple' object has no attribute 'append'# del t[0] # TypeError: 'tuple' object doesn't support item deletion
注意: 如果元组中包含可变对象(如列表),虽然元组本身不可变,但该可变对象的内容仍可以被修改。
t = ([1, 2], 3)t[0].append(3) # 修改了列表元素print(t) # ([1, 2, 3], 3) 元组本身没变,但内部列表变了
3.3 可以包含任意类型
元组中的元素可以是数字、字符串、布尔值、列表、字典,甚至其他元组。
mixed = (1, "hello", True, [2, 3], (4, 5))
3.4 可哈希性(若元素都是可哈希的)
如果元组中的所有元素都是不可变类型,那么该元组本身是可哈希的,可以作为字典的键或集合的元素。
# 元组作为字典键d = {(1, 2): "point1", (3, 4): "point2"}print(d[(1, 2)]) # point1# 元组作为集合元素s = {(1, 2), (3, 4)}print(s) # {(1, 2), (3, 4)}
如果元组中包含列表等可变对象,则元组不可哈希。
3.5 支持索引和切片
元组支持与列表相同的索引和切片操作,返回一个新的元组(切片的结果也是元组)。
t = (0, 1, 2, 3, 4, 5)print(t[1:4]) # (1, 2, 3)print(t[::-1]) # (5, 4, 3, 2, 1, 0)
3.6 支持常见序列操作
t1 = (1, 2, 3)t2 = (4, 5, 6)print(len(t1)) # 3print(2in t1) # Trueprint(t1 + t2) # (1, 2, 3, 4, 5, 6)print(t1 * 2) # (1, 2, 3, 1, 2, 3)print(t1.count(2)) # 1print(t1.index(3)) # 2
3.7 解包(元组拆包)
元组支持解包赋值,可以方便地将元组中的元素赋给多个变量。
point = (10, 20)x, y = pointprint(x, y) # 10 20# 也可以使用 * 收集多余元素numbers = (1, 2, 3, 4, 5)first, *rest = numbersprint(first) # 1print(rest) # [2, 3, 4, 5] 注意 rest 是列表
四、元组与列表的对比
五、为什么使用元组?
- 2. 性能:元组比列表更轻量,创建和访问速度略快。
- 3. 作为字典键:因为不可变,可以作为字典的键(列表不行)。
- 4. 函数多返回值:Python 函数返回多个值时,实际上返回的是元组。
- 5. 可读性:使用元组表明数据是固定的,如坐标、RGB 值等。
六、常见陷阱与注意事项
6.1 单元素元组必须加逗号
t = (5) # 不是元组,是整数5t = (5,) # 正确的单元素元组
6.2 元组不可变,但内部可变对象可变
t = ([1, 2], 3)t[0].append(3) # 合法,t 变成 ([1, 2, 3], 3)
6.3 使用 + 和 * 会生成新元组,原元组不变
t = (1, 2)t2 = t + (3, 4) # t 仍是 (1, 2),t2 是 (1, 2, 3, 4)
6.4 元组的比较
元组可以按字典序逐个比较元素。
print((1, 2) < (1, 3)) # Trueprint((2,) > (1, 10)) # True
6.5 命名元组(namedtuple)
Python 的 collections 模块提供了 namedtuple,可以创建带有字段名的元组,增强可读性。
from collections import namedtuplePoint = namedtuple('Point', ['x', 'y'])p = Point(10, 20)print(p.x, p.y) # 10 20print(p[0], p[1]) # 10 20(依然支持索引)
七、实战案例
案例1:坐标点与距离计算
p1 = (0, 0)p2 = (3, 4)# 计算欧氏距离distance = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5print(distance) # 5.0
案例2:多值返回
defmin_max(numbers):returnmin(numbers), max(numbers)data = [3, 1, 7, 2, 5]min_val, max_val = min_max(data)print(f"最小值:{min_val},最大值:{max_val}")
案例3:交换变量(利用元组解包)
a = 10b = 20a, b = b, a # 右侧 (b, a) 是元组,然后解包赋值给 a, bprint(a, b) # 20 10
案例4:使用元组作为字典键(缓存)
cache = {}deffactorial(n):if n in cache:return cache[n]if n < 2:return1 result = n * factorial(n-1) cache[n] = resultreturn result# 其实这里用元组键不明显,但可以用于多维缓存cache = {}deffibonacci(n):if n in cache:return cache[n]if n < 2:return n result = fibonacci(n-1) + fibonacci(n-2) cache[n] = resultreturn result
八、总结
- • 元组 是不可变的有序序列,用圆括号或逗号创建。
- • 一旦创建,不能修改元素,但若包含可变对象,该对象内部可变。
- • 当元素都不可变时,元组是可哈希的,可作为字典键。
- • 相比列表,元组更安全、更快,适合存储固定数据。
- • 常用场景:坐标、函数多返回值、字典键、数据记录等。
掌握元组,能让你写出更安全、更高效的 Python 代码。