元组与不可变序列
元组的创建
元组(tuple)是不可变的有序序列,用圆括号 () 表示:
# 创建元组
colors = ("红", "绿", "蓝")
numbers = (1, 2, 3, 4, 5)
mixed = (1, "hello", 3.14, True)
# 单元素元组(注意逗号)
single = (42,) # 这是元组
not_tuple = (42) # 这只是整数42
# 省略括号(元组打包)
point = 3, 4, 5
print(type(point)) # <class 'tuple'>
# 空元组
empty = ()
empty2 = tuple()
# 从其他类型转换
list_to_tuple = tuple([1, 2, 3])
str_to_tuple = tuple("Hello")
元组的基本操作
元组支持索引、切片、遍历等操作:
fruits = ("苹果", "香蕉", "橘子", "西瓜", "葡萄")
# 索引
print(fruits[0]) # 苹果
print(fruits[-1]) # 葡萄
# 切片
print(fruits[1:3]) # ('香蕉', '橘子')
print(fruits[::2]) # ('苹果', '橘子', '葡萄')
# 遍历
for fruit in fruits:
print(fruit)
# 长度
print(len(fruits)) # 5
# 检查成员
print("苹果" in fruits) # True
元组的方法
元组只有两个内置方法,因为它们是不可变的:
numbers = (1, 2, 3, 2, 4, 2, 5)
# count() - 统计出现次数
print(numbers.count(2)) # 3
# index() - 查找元素位置
print(numbers.index(4)) # 4
元组 vs 列表
| 特性 | 元组 | 列表 |
|---|---|---|
| 可变性 | 不可变 | 可变 |
| 语法 | () |
[] |
| 性能 | 更快,内存占用更少 | 较慢 |
| 可作为字典键 | 是 | 否 |
| 用途 | 固定数据集合 | 需要修改的数据集合 |
# 元组不可变
t = (1, 2, 3)
# t[0] = 99 # TypeError!
# 列表可变
l = [1, 2, 3]
l[0] = 99 # 正确
元组解包
元组解包是将元组的元素同时赋给多个变量:
# 基本解包
point = (3, 4)
x, y = point
print(f"x={x}, y={y}") # x=3, y=4
# 交换变量(利用元组解包)
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
# 多变量解包
name, age, city = "小明", 25, "北京"
print(f"{name}今年{age}岁,住在{city}")
# 使用 * 收集剩余元素
first, *rest = (1, 2, 3, 4, 5)
print(first) # 1
print(rest) # [2, 3, 4, 5]
*head, last = (1, 2, 3, 4, 5)
print(head) # [1, 2, 3, 4]
print(last) # 5
first, *middle, last = (1, 2, 3, 4, 5)
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
元组的实际应用
函数返回多个值
def get_min_max(numbers):
return min(numbers), max(numbers)
minimum, maximum = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(f"最小值: {minimum}, 最大值: {maximum}")
def divide(a, b):
if b == 0:
return None, "除数不能为零"
return a / b, "计算成功"
result, message = divide(10, 3)
print(f"{result:.2f} - {message}")
作为字典的键
# 元组可以作为字典键(因为不可变)
locations = {
(39.9, 116.4): "北京",
(31.2, 121.5): "上海",
(23.1, 113.3): "广州"
}
print(locations[(39.9, 116.4)]) # 北京
# 列表不能作为字典键
# { [1, 2]: "value" } # TypeError!
作为字典项
# 元组常用于表示记录
students = [
("小明", 85),
("小红", 92),
("小刚", 78),
("小丽", 95)
]
for name, score in students:
print(f"{name}: {score}分")
函数参数解包
def greet(name, age, city):
print(f"你好,我是{name},今年{age}岁,来自{city}")
info = ("小明", 25, "北京")
greet(*info) # 使用 * 解包元组作为参数
命名元组
Python标准库提供了命名元组,增加可读性:
from collections import namedtuple
# 定义命名元组
Point = namedtuple("Point", ["x", "y"])
Student = namedtuple("Student", "name age score")
# 使用
p = Point(3, 4)
print(p.x, p.y) # 3 4
s = Student("小明", 25, 95)
print(f"{s.name}的成绩是{s.score}")
元组的性能优势
import sys
# 内存对比
list_example = [1, 2, 3, 4, 5]
tuple_example = (1, 2, 3, 4, 5)
print(sys.getsizeof(list_example)) # 104 字节
print(sys.getsizeof(tuple_example)) # 80 字节
# 创建速度对比
import timeit
list_time = timeit.timeit("[1, 2, 3, 4, 5]", number=1000000)
tuple_time = timeit.timeit("(1, 2, 3, 4, 5)", number=1000000)
print(f"列表: {list_time:.4f}秒")
print(f"元组: {tuple_time:.4f}秒")
何时使用元组
- 数据不需要修改时(如坐标、RGB颜色值)
- 需要作为字典键时
- 函数需要返回多个值时
- 追求性能和内存效率时
- 表示固定结构的记录时
总结
元组是不可变的有序序列,虽然功能比列表少,但在特定场景下更高效、更安全。理解元组与列表的区别,能帮助你选择合适的数据结构。下一节我们将学习字典——Python中最重要的映射类型。