Python 教程 13:元组
“不变,有时候是一种力量。”
元组和列表很像,但有一个关键区别:元组是不可变的。这个特性让元组在某些场景下比列表更安全、更高效。
1. 什么是元组
元组(Tuple)是一个有序的、不可变的元素集合。
1# 创建元组
2empty_tuple = () # 空元组
3single = (1,) # 单元素元组(注意逗号)
4numbers = (1, 2, 3, 4, 5)
5mixed = (1, "hello", 3.14, True)
6nested = ((1, 2), (3, 4))
7
8# 也可以不用括号(但不推荐)
9point = 10, 20
10print(point) # (10, 20)
11
12# 使用tuple()函数
13from_list = tuple([1, 2, 3])
14from_string = tuple("Python") # ('P', 'y', 't', 'h', 'o', 'n')
注意:单元素元组必须有逗号!
1not_a_tuple = (1) # 这是整数1
2is_a_tuple = (1,) # 这才是元组
2. 访问元组元素
元组的访问方式和列表完全相同:
1fruits = ("苹果", "香蕉", "橙子", "葡萄")
2
3# 索引
4print(fruits[0]) # 苹果
5print(fruits[-1]) # 葡萄
6
7# 切片
8print(fruits[1:3]) # ('香蕉', '橙子')
9print(fruits[::-1]) # ('葡萄', '橙子', '香蕉', '苹果')
10
11# 遍历
12for fruit in fruits:
13 print(fruit)
14
15# enumerate
16for i, fruit in enumerate(fruits):
17 print(f"{i}: {fruit}")
3. 元组的不可变性
元组创建后不能修改:
1numbers = (1, 2, 3)
2
3# 不能修改元素
4# numbers[0] = 10 # TypeError
5
6# 不能添加元素
7# numbers.append(4) # AttributeError
8
9# 不能删除元素
10# del numbers[0] # TypeError
但如果元组包含可变对象,可变对象本身可以修改:
1# 元组包含列表
2data = (1, 2, [3, 4])
3
4# 不能修改元组本身
5# data[0] = 10 # TypeError
6
7# 但可以修改列表
8data[2].append(5)
9print(data) # (1, 2, [3, 4, 5])
10
11# 元组本身没变(还是3个元素),但列表内容变了
4. 元组的方法
元组只有两个方法(比列表少得多):
1numbers = (1, 2, 3, 2, 1, 2)
2
3# count():统计元素出现次数
4print(numbers.count(2)) # 3
5
6# index():查找元素索引
7print(numbers.index(3)) # 2
8
9# 其他操作
10print(len(numbers)) # 6
11print(max(numbers)) # 3
12print(min(numbers)) # 1
13print(sum(numbers)) # 11
14
15# 成员测试
16print(2 in numbers) # True
5. 元组解包(Unpacking)
元组的一个强大特性:解包
1# 基本解包
2point = (10, 20)
3x, y = point
4print(x, y) # 10 20
5
6# 交换变量(Python的优雅写法)
7a, b = 1, 2
8a, b = b, a # 交换
9print(a, b) # 2 1
10
11# 多重赋值
12name, age, city = ("张三", 25, "北京")
13
14# 扩展解包(Python 3.0+)
15numbers = (1, 2, 3, 4, 5)
16first, *middle, last = numbers
17print(first) # 1
18print(middle) # [2, 3, 4](注意:是列表)
19print(last) # 5
20
21# 忽略某些值
22x, _, z = (1, 2, 3) # _表示不关心的值
6. 元组 vs 列表
| 特性 | 元组 | 列表 |
|---|---|---|
| 可变性 | 不可变 | 可变 |
| 语法 | () | [] |
| 性能 | 快(稍微) | 慢(稍微) |
| 方法数 | 2 个 | 十几个 |
| 用途 | 固定数据、字典键 | 动态数据 |
什么时候用元组:
- 数据不应该被修改(如坐标、日期)
- 作为字典的键
- 函数返回多个值
- 性能要求高(元组稍快)
什么时候用列表:
- 数据需要修改
- 需要添加/删除元素
- 需要排序等操作
7. 元组的实际应用
应用 1:函数返回多个值
1def get_user_info():
2 """返回用户信息"""
3 name = "张三"
4 age = 25
5 city = "北京"
6 return name, age, city # 实际返回的是元组
7
8# 接收返回值
9user_name, user_age, user_city = get_user_info()
10print(f"{user_name}, {user_age}岁, {user_city}")
应用 2:作为字典的键
1# 坐标作为键
2locations = {
3 (0, 0): "原点",
4 (1, 0): "右",
5 (0, 1): "上"
6}
7
8print(locations[(1, 0)]) # 右
9
10# 列表不能作为键
11# bad = {[1, 2]: "value"} # TypeError
应用 3:保护数据
1# 配置数据(不应修改)
2CONFIG = (
3 "localhost",
4 8080,
5 "/api/v1"
6)
7
8# 尝试修改会报错
9# CONFIG[0] = "127.0.0.1" # TypeError
8. 命名元组(NamedTuple)
普通元组的问题:难以记住每个位置的含义
1# 普通元组
2person = ("张三", 25, "北京")
3print(person[0]) # 张三,但0是什么意思?
命名元组可以给每个位置一个名字:
1from collections import namedtuple
2
3# 定义命名元组
4Person = namedtuple('Person', ['name', 'age', 'city'])
5
6# 创建实例
7person = Person("张三", 25, "北京")
8
9# 访问:可以用名字,也可以用索引
10print(person.name) # 张三
11print(person[0]) # 张三
12print(person.age) # 25
13print(person.city) # 北京
14
15# 转换为字典
16print(person._asdict())
17# OrderedDict([('name', '张三'), ('age', 25), ('city', '北京')])
18
19# 替换字段(返回新对象)
20person2 = person._replace(age=26)
21print(person2) # Person(name='张三', age=26, city='北京')
命名元组结合了元组的不可变性和类的可读性。
9. 小结
今天我们学习了元组:
- 特性:不可变、有序
- 创建:
()、tuple(),单元素要逗号 - 访问:索引、切片,和列表相同
- 方法:count()、index()
- 解包:多重赋值、*扩展解包
- 对比:元组不可变、列表可变
- 应用:函数返回值、字典键、保护数据
- 命名元组:增强可读性
元组虽然简单,但在合适的场景下能让代码更安全、更高效。
练习题:
- 写一个函数,返回三个值:最小值、最大值、平均值
- 用元组交换两个变量的值(一行代码)
- 创建一个命名元组表示学生(姓名、学号、成绩)
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
