元组(Tuples)
不可变的列表 —— 用于存储固定数据
什么是元组?
元组(Tuple)是 Python 中的不可变序列,类似于列表,但创建后不能修改。
列表 vs 元组
| 特性 | 列表(List) | 元组(Tuple) |
|---|---|---|
| 语法 | [1, 2, 3] | (1, 2, 3) |
| 可变性 | 可修改 | 不可修改 |
| 速度 | 较慢 | 较快 |
| 用途 | 动态数据 | 固定数据 |
什么时候用元组?
- 数据不应被修改(如坐标、日期)
- 作为字典的键(列表不行)
- 函数返回多个值
创建元组
1. 基本创建
python
# 空元组
empty_tuple = ()
# 单个元素(注意逗号!)
single = (5,) # 这是元组
not_tuple = (5) # 这只是数字 5
# 多个元素
coordinates = (10, 20)
student_info = ("Alice", 25, "Economics")
# 不用括号也行(但不推荐)
point = 10, 20
print(type(point)) # <class 'tuple'>2. 从列表转换
python
ages_list = [25, 30, 35]
ages_tuple = tuple(ages_list)
print(ages_tuple) # (25, 30, 35)访问元组元素
索引和切片(与列表相同)
python
student = ("Alice", 25, "Economics", 3.85)
# 索引访问
print(student[0]) # Alice
print(student[-1]) # 3.85
# 切片
print(student[1:3]) # (25, 'Economics')
print(student[:2]) # ('Alice', 25)元组解包(Unpacking)
python
# 基本解包
point = (10, 20)
x, y = point
print(f"x={x}, y={y}") # x=10, y=20
# 多变量解包
student = ("Alice", 25, "Economics")
name, age, major = student
print(name, age, major) # Alice 25 Economics
# 部分解包(使用 *)
scores = (85, 90, 78, 92, 88)
first, second, *rest = scores
print(first) # 85
print(second) # 90
print(rest) # [78, 92, 88](注意:rest 是列表!)社科应用:
python
# 调查数据:(ID, 性别, 年龄, 收入)
respondent = (1001, "Female", 30, 75000)
# 解包
resp_id, gender, age, income = respondent
print(f"受访者 {resp_id}: {gender}, {age}岁, 收入${income:,}")元组的不可变性
python
student = ("Alice", 25, "Economics")
# 不能修改
student[1] = 26 # TypeError: 'tuple' object does not support item assignment
# 不能添加
student.append("GPA") # AttributeError: 'tuple' object has no attribute 'append'
# 不能删除
del student[0] # TypeError
# 可以整个替换
student = ("Bob", 28, "Sociology")为什么需要不可变?
- 防止意外修改重要数据
- 可以作为字典的键
- 更快的性能
元组操作
1. 基本操作
python
numbers = (1, 2, 3, 4, 5, 2, 3)
# 长度
print(len(numbers)) # 7
# 最大/最小/求和
print(max(numbers)) # 5
print(min(numbers)) # 1
print(sum(numbers)) # 20
# 计数
print(numbers.count(2)) # 2
# 查找索引
print(numbers.index(3)) # 2(第一次出现的位置)
# 检查存在
print(2 in numbers) # True2. 连接和重复
python
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
# 连接
combined = tuple1 + tuple2
print(combined) # (1, 2, 3, 4, 5, 6)
# 重复
repeated = tuple1 * 3
print(repeated) # (1, 2, 3, 1, 2, 3, 1, 2, 3)实战案例
案例 1:地理坐标
python
# 城市坐标(经度,纬度)
cities = {
"Beijing": (39.9042, 116.4074),
"Shanghai": (31.2304, 121.4737),
"Guangzhou": (23.1291, 113.2644)
}
# 计算北京和上海的距离(简化版)
import math
def calculate_distance(coord1, coord2):
lat1, lon1 = coord1
lat2, lon2 = coord2
# 简化的距离计算
distance = math.sqrt((lat2 - lat1)**2 + (lon2 - lon1)**2)
return distance * 111 # 转换为公里(粗略)
beijing = cities["Beijing"]
shanghai = cities["Shanghai"]
dist = calculate_distance(beijing, shanghai)
print(f"北京到上海距离约: {dist:.0f} 公里")案例 2:问卷元数据
python
# 问卷基本信息(不应被修改)
survey_metadata = (
"中国居民收入调查", # 问卷名称
"2024-01-01", # 开始日期
"2024-12-31", # 结束日期
1000, # 目标样本量
"中文" # 语言
)
# 解包
name, start_date, end_date, target_n, language = survey_metadata
print(f"=== 问卷信息 ===")
print(f"名称: {name}")
print(f"周期: {start_date} 至 {end_date}")
print(f"目标样本: {target_n}")
print(f"语言: {language}")案例 3:函数返回多值
python
def calculate_statistics(data):
"""计算描述性统计,返回元组"""
n = len(data)
mean = sum(data) / n
sorted_data = sorted(data)
median = sorted_data[n//2]
minimum = min(data)
maximum = max(data)
return (n, mean, median, minimum, maximum)
# 使用
scores = [85, 92, 78, 90, 88, 76, 95, 82]
n, mean, median, min_val, max_val = calculate_statistics(scores)
print(f"样本量: {n}")
print(f"平均数: {mean:.2f}")
print(f"中位数: {median}")
print(f"最小值: {min_val}")
print(f"最大值: {max_val}")元组与列表的转换
python
# 列表转元组
ages_list = [25, 30, 35, 40]
ages_tuple = tuple(ages_list)
print(ages_tuple) # (25, 30, 35, 40)
# 元组转列表
ages_tuple = (25, 30, 35, 40)
ages_list = list(ages_tuple)
print(ages_list) # [25, 30, 35, 40]实用场景:需要修改元组时
python
# 原始元组
student = ("Alice", 25, "Economics")
# 转为列表修改
student_list = list(student)
student_list[1] = 26 # 修改年龄
student = tuple(student_list) # 转回元组
print(student) # ('Alice', 26, 'Economics')高级应用:命名元组(namedtuple)
普通元组的问题:只能用索引访问,不够直观。
python
from collections import namedtuple
# 定义命名元组
Student = namedtuple('Student', ['name', 'age', 'major', 'gpa'])
# 创建实例
alice = Student(name="Alice", age=25, major="Economics", gpa=3.85)
# 访问(两种方式)
print(alice.name) # Alice(更直观)
print(alice[0]) # Alice(也可以用索引)
print(alice.gpa) # 3.85
print(alice[-1]) # 3.85
# 仍然是元组,不可修改
# alice.age = 26 # AttributeError社科应用:
python
from collections import namedtuple
# 定义调查响应结构
Response = namedtuple('Response', [
'respondent_id',
'age',
'gender',
'income',
'education',
'satisfaction'
])
# 创建响应
resp1 = Response(
respondent_id=1001,
age=30,
gender="Female",
income=75000,
education="Bachelor's",
satisfaction=4
)
# 直观访问
print(f"受访者 {resp1.respondent_id}:")
print(f" 年龄: {resp1.age}")
print(f" 收入: ${resp1.income:,}")
print(f" 满意度: {resp1.satisfaction}/5")何时用列表 vs 元组?
| 场景 | 使用列表 | 使用元组 |
|---|---|---|
| 收集受访者年龄 | ages = [25, 30, ...] | |
| 地理坐标 | point = (39.9, 116.4) | |
| 问卷元数据 | metadata = ("调查", "2024") | |
| 动态添加数据 | data.append(x) | |
| 函数返回多值 | return (mean, std, n) | |
| 作为字典键 | {(x, y): value} |
经验法则:
- 数据会变 → 用列表
- 数据不变 → 用元组
常见错误
错误 1:忘记单元素元组的逗号
python
# 不是元组
single = (5)
print(type(single)) # <class 'int'>
# 是元组
single = (5,)
print(type(single)) # <class 'tuple'>错误 2:尝试修改元组
python
coords = (10, 20)
coords[0] = 15 # TypeError: 'tuple' object does not support item assignment错误 3:元组与列表混淆
python
# 元组没有 append 方法
numbers = (1, 2, 3)
numbers.append(4) # AttributeError
# 应该用列表
numbers = [1, 2, 3]
numbers.append(4) #练习题
练习 1:RGB 颜色
python
# 定义几个颜色(RGB元组)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
# 任务:
# 1. 创建一个函数,接受 RGB 元组,返回颜色名称
# 2. 计算红色和绿色的"距离"(欧氏距离)练习 2:学生记录
python
# 使用命名元组创建学生记录系统
# 字段: id, name, age, major, gpa
# 创建3个学生,计算平均GPA练习 3:函数返回多值
python
# 编写函数计算收入的四分位数
incomes = [45000, 50000, 60000, 75000, 80000, 95000, 120000, 150000]
# 函数返回 (Q1, Q2, Q3) 作为元组
# 提示:排序后取 25%, 50%, 75% 位置下一步
在下一节中,我们将学习 字典(Dictionaries),Python 最强大的数据结构之一,类似于 R 的 named list。
继续前进!