第四章:元组
4.1 什么是元组?
元组就像 一个上了锁的集装箱,一旦创建,就不能再修改里面的内容。它和列表很像,但最大的区别是:元组是不可变的。元组用小括号()创建。
# 创建元组。
coordinates = (10, 20);
colors = ("红色", "绿色", "蓝色");
single_item = (42,); # 注意:单个元素的元组需要加逗号。
4.2 元组的创建方式
元组可以用多种方式创建:
# 直接使用圆括号创建
point = (3, 4)
# 可以省略圆括号(逗号分隔的多个值会自动组成元组)
dimensions = 100, 200
print(type(dimensions)) # <class 'tuple'>
# 使用tuple()函数从其他序列创建
numbers = tuple([1, 2, 3, 4, 5]) # (1, 2, 3, 4, 5)
chars = tuple("hello") # ('h', 'e', 'l', 'l', 'o')
# 创建空元组
empty_tuple = (); # 方法1。
empty_tuple2 = tuple(); # 方法2。
4.3 元组的基本操作
4.3.1 访问元组元素
元组支持索引和切片,就像列表一样:
colors = ("红色", "绿色", "蓝色", "黄色", "紫色");
print(colors[0]); # 红色 - 第一个元素
print(colors[-1]); # 紫色 - 最后一个元素
print(colors[1:4]); # ('绿色', '蓝色', '黄色') - 切片操作。
4.3.2 元组长度
使用 len() 函数获取元组长度:
colors = ("红色", "绿色", "蓝色")
print(len(colors)) # 3
4.3.3 检查元素是否存在
使用 in 关键字检查元素是否在元组中:
colors = ("红色", "绿色", "蓝色")
print("红色" in colors) # True
print("黑色" in colors) # False
4.3.4 元组的不可变性
元组一旦创建就不能修改,这是它与列表最大的区别:
colors = ("红色", "绿色", "蓝色")
# 以下操作都会报错!
# colors[0] = "黑色" # 不能修改元素
# colors.append("黄色") # 不能添加元素
# colors.remove("红色") # 不能删除元素
4.4 元组的常用方法
由于元组是不可变的,它的方法比列表少很多:
numbers = (1, 2, 3, 2, 4, 2, 5)
# count() - 统计元素出现的次数
print(numbers.count(2)) # 3
# index() - 返回元素的索引位置
print(numbers.index(3)) # 2
print(numbers.index(2, 2)) # 3 - 从索引2开始查找
4.5 元组的遍历
遍历元组的方式与列表相同:
colors = ("红色", "绿色", "蓝色")
# 直接遍历元素
for color in colors:
print(f"颜色:{color}")
# 遍历索引和元素
for i, color in enumerate(colors):
print(f"第{i}个颜色是:{color}")
4.6 元组的解包
元组解包是Python中一个很有用的特性:
# 基本解包。
point = (10, 20);
x, y = point;
print(f"x={x}, y={y}"); # x=10, y=20。
# 解包时使用*收集剩余元素。
numbers = (1, 2, 3, 4, 5);
first, *middle, last = numbers;
print(first); # 1。
print(middle); # [2, 3, 4]。
print(last); # 5。
# 交换变量的值(实际上使用了元组解包)
a, b = 10, 20
a, b = b, a
print(f"a={a}, b={b}") # a=20, b=10
4.7 元组与列表的比较
| 特性 | 列表 | 元组 |
|---|---|---|
| 可变性 | 可变 | 不可变 |
| 语法 | 方括号 [] | 圆括号 () |
| 性能 | 较慢 | 较快 |
| 安全性 | 较低 | 较高 |
| 内存占用 | 较大 | 较小 |
| 用途 | 存储可能变化的数据 | 存储不应变化的数据 |
4.8 元组的应用场景
4.8.1 函数返回多个值
def calculate_stats(numbers):
"""计算数字列表的统计信息"""
total = sum(numbers)
count = len(numbers)
average = total / count
return total, count, average # 返回一个元组
result = calculate_stats([1, 2, 3, 4, 5])
print(result) # (15, 5, 3.0)
# 解包返回值
total, count, average = calculate_stats([1, 2, 3, 4, 5])
print(f"总和:{total}, 数量:{count}, 平均值:{average}")
4.8.2 作为字典的键
由于元组是不可变的,它可以作为字典的键,而列表不行:
# 元组可以作为字典的键。
coordinates_map = {
(0, 0): "原点",
(1, 0): "X轴上",
(0, 1): "Y轴上"
};
print(coordinates_map[(0, 0)]); # 原点。
# 列表不能作为字典的键(会报错)。
# invalid_dict = {[1, 2]: "值"}。
4.8.3 存储不应修改的数据
# 颜色常量
COLORS = ("红色", "绿色", "蓝色")
# 月份名称
MONTHS = ("一月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "十一月", "十二月")
# 配置信息
DATABASE_CONFIG = ("localhost", 3306, "my_database", "username", "password")
4.9 元组与列表的转换
元组和列表可以相互转换:
# 列表转元组
fruits_list = ["苹果", "香蕉", "橙子"]
fruits_tuple = tuple(fruits_list)
print(fruits_tuple) # ('苹果', '香蕉', '橙子')
# 元组转列表
colors_tuple = ("红色", "绿色", "蓝色")
colors_list = list(colors_tuple)
print(colors_list) # ['红色', '绿色', '蓝色']
4.10 命名元组
collections 模块中的 namedtuple 可以创建带有字段名的元组:
from collections import namedtuple
# 创建一个命名元组类型
Point = namedtuple("Point", ["x", "y"])
# 创建命名元组实例
p1 = Point(10, 20)
p2 = Point(x=30, y=40)
print(p1.x, p1.y) # 10 20
print(p2.x, p2.y) # 30 40
# 仍然支持普通的元组操作
print(p1[0], p1[1]) # 10 20
4.11 元组的性能优势
由于元组是不可变的,它在某些情况下比列表更高效:
import sys
import time
# 内存占用比较
numbers_list = [1, 2, 3, 4, 5]
numbers_tuple = (1, 2, 3, 4, 5)
print(f"列表占用内存: {sys.getsizeof(numbers_list)} 字节")
print(f"元组占用内存: {sys.getsizeof(numbers_tuple)} 字节")
# 创建速度比较(通常元组稍快)
start_time = time.time()
for _ in range(1000000):
[1, 2, 3, 4, 5]
list_time = time.time() - start_time
start_time = time.time()
for _ in range(1000000):
(1, 2, 3, 4, 5)
tuple_time = time.time() - start_time
print(f"列表创建时间: {list_time:.6f} 秒")
print(f"元组创建时间: {tuple_time:.6f} 秒")
本章笔记:
- 元组是不可变的序列,一旦创建就不能修改。
- 元组使用圆括号创建,但也可以省略圆括号。
- 支持索引、切片、长度检查等基本操作。
- 元组的方法很少,主要是count()和index()。
- 元组解包是一个有用的特性,可以方便地提取元组中的值。
- 元组比列表更安全、更高效,适合存储不应修改的数据。
- 元组可以作为字典的键,而列表不行。
- 函数可以使用元组返回多个值。
- 命名元组提供了更友好的字段访问方式。
- 元组和列表可以相互转换。