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 个十几个
用途固定数据、字典键动态数据

什么时候用元组

  1. 数据不应该被修改(如坐标、日期)
  2. 作为字典的键
  3. 函数返回多个值
  4. 性能要求高(元组稍快)

什么时候用列表

  1. 数据需要修改
  2. 需要添加/删除元素
  3. 需要排序等操作

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()
  • 解包:多重赋值、*扩展解包
  • 对比:元组不可变、列表可变
  • 应用:函数返回值、字典键、保护数据
  • 命名元组:增强可读性

元组虽然简单,但在合适的场景下能让代码更安全、更高效。


练习题

  1. 写一个函数,返回三个值:最小值、最大值、平均值
  2. 用元组交换两个变量的值(一行代码)
  3. 创建一个命名元组表示学生(姓名、学号、成绩)

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读