Z
ZHANK
数据结构

元组 (Tuple)

了解元组不可变特性、拆包技巧、与列表的区别

元组 (Tuple)

元组和列表很像,但有一个关键区别:元组不可修改。这个看似"限制"的特性,恰好是它的最大优势。

学完本章你将掌握: 元组创建、拆包、不可变性、命名元组、与列表的选择。


一、创建元组

python
# 圆括号创建
t1 = (1, 2, 3)

# 可以省略括号
t2 = "a", "b", "c"

# 单元素元组(注意逗号!)
single = (42,)   # 这是元组
not_tuple = (42) # 这只是整数 42!

# tuple() 构造函数
t3 = tuple([3, 1, 4])  # 从列表创建
t4 = tuple("hello")    # ('h','e','l','l','o')

💡 单元素陷阱(42) 被解析为数学表达式的括号,不是元组。必须加逗号 (42,)


二、访问元素

与列表完全相同的索引和切片:

python
point = (10, 20, 30, 40)

print(point[0])     # 10
print(point[-1])    # 40
print(point[1:3])   # (20, 30)
print(len(point))   # 4

三、不可变性

python
t = (1, 2, 3)

# ❌ 这些操作都会报错
# t[0] = 10        # TypeError: 'tuple' object does not support item assignment
# t.append(4)      # AttributeError
# t.remove(1)      # AttributeError

# ✅ 只能读取和计算
print(1 in t)       # True
print(t.count(2))   # 1
print(t.index(3))   # 2
print(sum(t))       # 6
print(max(t))       # 3

💡 不可变的好处:数据不会被意外修改,可以安全地用作字典的键;多线程环境下不需要加锁。


四、元组拆包

Python 最优雅的特性之一:

python
# 基础拆包
name, age, city = ("小明", 20, "北京")
print(f"{name}{age}岁,来自{city}")

# 交换变量(无需临时变量!)
a, b = 10, 20
a, b = b, a
print(a, b)  # 20 10

# 星号拆包(收集剩余元素)
first, *middle, last = (1, 2, 3, 4, 5)
print(first)   # 1
print(middle)  # [2, 3, 4](中间是列表)
print(last)    # 5

# 忽略不需要的值(用 _)
name, _, city = ("小明", 20, "北京")
print(name, city)  # 小明 北京

实战:函数返回多个值:

python
def divide(a, b):
    quotient = a // b
    remainder = a % b
    return quotient, remainder  # 实际返回元组

q, r = divide(10, 3)
print(f"商 {q},余 {r}")  # 商 3,余 1

五、元组 vs 列表

特性列表元组
创建`[1,2,3]``(1,2,3)`
修改✅ 可增删改❌ 不可修改
性能稍慢稍快
内存更大更小
作字典键❌ 不能✅ 可以
适用场景动态数据固定数据
python
# 什么时候用元组?
# 1. 坐标、颜色值等固定数据
point = (1920, 1080)
rgb = (255, 128, 0)

# 2. 数据库查询结果
user = (1, "小明", "beijing")

# 3. 需要保护的常量
STATUS_CODES = (200, 301, 404, 500)

六、命名元组 namedtuple

让元组像对象一样通过名字访问:

python
from collections import namedtuple

# 定义一个"学生"命名元组
Student = namedtuple("Student", ["name", "age", "score"])

s1 = Student("小明", 20, 95)
s2 = Student("小红", 22, 88)

# 像属性一样访问
print(s1.name)    # 小明
print(s1.score)   # 95
print(s2.age)     # 22

# 仍然是元组,可以用索引
print(s1[0])      # 小明

小结

  1. 元组用 (),不可修改——这是它和列表的唯一核心区别
  2. 拆包 a, b = (1, 2) 简洁优雅
  3. 星号拆包 *middle 收集剩余元素
  4. 需要不可变数据时优先用元组(更安全、更快)
  5. namedtuple 结合了元组的轻量和对象的可读性

小练习

  1. 用拆包交换两个变量的值
  2. 写一个函数 min_max(nums) 返回元组(最小值, 最大值)
  3. 创建一个 Point 命名元组,包含 x, y 坐标

💬 下一章预告:接下来学习集合 (Set)——自动去重的数据结构。