程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

    • 环境搭建
    • 标识符
    • 变量
    • 缩进和注释
    • 数据类型
    • 数据类型转换
    • 运算符
    • 字符串
    • 列表
    • 元组
      • 1. 元组的核心特性
      • 2. 创建元组:简单但有陷阱
        • 2.1 使用小括号 ()
        • 2.2 小括号的省略
        • 2.3 新手陷阱:创建单元素元组
        • 2.4 使用 tuple() 构造函数
      • 3. 访问与操作
        • 3.1 访问与切片
        • 3.2 遍历元组
        • 3.3 常用方法: count() 和 index()
        • 3.4 常用运算符: +, *, in
      • 4. 元组解包:优雅地赋值
        • 4.1 基础解包
        • 4.2 动态解包 (星号 *)
        • 4.3 解包的经典应用
      • 5. “不可变”的深入理解
        • 5.1 元组中的可变对象
      • 6. 元组的应用场景与优势
        • 6.1 为什么要使用元组?
        • 6.2 核心应用场景
      • 7. 进阶:命名元组 (namedtuple)
    • 字典
    • 集合
    • if判断
    • for循环
    • while循环
    • 循环综合练习
    • Python函数
    • 函数与循环实战
    • 生成式
    • 文件读写
    • 面向对象
    • 面向对象综合案例
  • Python 进阶

  • Python
  • Python 基础
scholar
2025-07-20
目录

元组

# 元组(Tuple)


# 1. 元组的核心特性

元组(Tuple)是一种与列表非常相似的数据结构,但它有一个最关键的区别:元组是不可变的 (Immutable)。

你可以把元组想象成一个上了锁的透明盒子:

  • 有序 (Ordered): 盒子里的物品有固定的顺序,你可以通过位置(索引)查看它们。
  • 不可变 (Immutable): 一旦物品放进去并锁上,你就不能替换、增加或删除任何物品。
  • 异构 (Heterogeneous): 盒子里可以存放任何类型的物品(数字、字符串、其他盒子等)。

这个“不可变”的特性使得元组在很多场景下比列表更安全、更高效。


# 2. 创建元组:简单但有陷阱

# 2.1 使用小括号 ()

这是创建元组最常见的方式。

# 创建一个空元组
empty_tuple = ()
print(f"空元组: {empty_tuple}") # 输出: 空元组: ()

# 创建一个包含多个元素的元组
fruits = ("apple", "banana", "cherry")
print(f"水果元组: {fruits}") # 输出: 水果元组: ('apple', 'banana', 'cherry')

# 创建一个混合类型的元组
mixed_tuple = (1, "hello", 3.14, True)
print(f"混合元组: {mixed_tuple}") # 输出: 混合元组: (1, 'hello', 3.14, True)
1
2
3
4
5
6
7
8
9
10
11

# 2.2 小括号的省略

在很多情况下,只要用逗号分隔元素,即使没有小括号,Python 也会默认将其视为一个元组。

# 这种写法也会创建一个元组
my_tuple = 10, 20, "world"
print(f"省略括号创建的元组: {my_tuple}") # 输出: 省略括号创建的元组: (10, 20, 'world')
print(f"它的类型是: {type(my_tuple)}")   # 输出: 它的类型是: <class 'tuple'>
1
2
3
4

开发者提示: 这种省略括号的写法在函数返回多个值时非常常见。

# 2.3 新手陷阱:创建单元素元组

这是初学者最容易犯错的地方。如果你想创建一个只包含一个元素的元组,必须在该元素后面加上一个逗号 ,。

# 错误的方式:这不会创建元组,而是一个普通的整数
wrong_single = (42) 
print(f"错误方式的类型: {type(wrong_single)}") # 输出: 错误方式的类型: <class 'int'>

# 正确的方式:必须有逗号
correct_single = (42,)
print(f"正确方式创建的元组: {correct_single}") # 输出: 正确方式创建的元组: (42,)
print(f"正确方式的类型: {type(correct_single)}") # 输出: 正确方式的类型: <class 'tuple'>
1
2
3
4
5
6
7
8

为什么? 因为小括号 () 在 Python 中也用于改变运算优先级,如 (3 + 5) * 2。为了区分运算优先级和单元素元组,Python 规定用逗号作为明确的元组创建标志。

# 2.4 使用 tuple() 构造函数

tuple() 函数可以将任何可迭代对象(如列表、字符串、range对象等)转换为元组。

# 从列表创建元组
my_list = [1, 2, 3]
list_to_tuple = tuple(my_list)
print(f"从列表转换: {list_to_tuple}") # 输出: 从列表转换: (1, 2, 3)

# 从字符串创建元组
char_tuple = tuple("hello")
print(f"从字符串转换: {char_tuple}") # 输出: 从字符串转换: ('h', 'e', 'l', 'l', 'o')
1
2
3
4
5
6
7
8

# 3. 访问与操作

由于元组不可变,它的方法比列表少得多,主要集中在查询上。

# 3.1 访问与切片

这部分的操作与列表完全相同。

numbers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

# 访问单个元素
print(f"第一个元素: {numbers[0]}") # 输出: 第一个元素: 0
print(f"最后一个元素: {numbers[-1]}") # 输出: 最后一个元素: 9

# 切片 (返回一个新的元组)
sub_tuple = numbers[2:5]
print(f"切片结果: {sub_tuple}") # 输出: 切片结果: (2, 3, 4)
1
2
3
4
5
6
7
8
9

# 3.2 遍历元组

使用 for 循环遍历元组,与遍历列表的方式一样。

for item in ("apple", "banana", "cherry"):
    print(f"当前水果: {item}")
# 输出:
# 当前水果: apple
# 当前水果: banana
# 当前水果: cherry
1
2
3
4
5
6

# 3.3 常用方法: count() 和 index()

元组只有两个主要的方法:

  • count(value): 统计 value 在元组中出现的次数。
  • index(value): 查找 value 在元组中首次出现时的索引。如果找不到,会抛出 ValueError。
data = (10, 20, 30, 20, 40, 20)
print(f"数字 20 出现了 {data.count(20)} 次") # 输出: 数字 20 出现了 3 次
print(f"数字 30 的索引是: {data.index(30)}")   # 输出: 数字 30 的索引是: 2
1
2
3

# 3.4 常用运算符: +, *, in

  • +: 连接两个元组,生成一个新元组。
  • *: 重复元组内容,生成一个新元组。
  • in: 检查元素是否存在于元组中。
tuple_a = (1, 2)
tuple_b = (3, 4)

# 连接
result = tuple_a + tuple_b
print(f"连接结果: {result}") # 输出: 连接结果: (1, 2, 3, 4)

# 重复
repeated = tuple_a * 3
print(f"重复结果: {repeated}") # 输出: 重复结果: (1, 2, 1, 2, 1, 2)

# 成员检测
print(f"3 是否在 tuple_b 中? {3 in tuple_b}") # 输出: 3 是否在 tuple_b 中? True
1
2
3
4
5
6
7
8
9
10
11
12
13

# 4. 元组解包:优雅地赋值

元组解包(Tuple Unpacking)是一种极其方便的特性,允许你将元组中的元素一次性地赋值给多个变量。

# 4.1 基础解包

变量数量必须与元组元素数量完全匹配。

# x, y, z 将分别被赋值为 10, 20, 30
point = (10, 20, 30)
x, y, z = point

print(f"x={x}, y={y}, z={z}") # 输出: x=10, y=20, z=30
1
2
3
4
5

# 4.2 动态解包 (星号 *)

当你只想获取部分元素,并将其余的元素收集到一个列表中时,可以使用 *。

numbers = (1, 2, 3, 4, 5, 6)

# 获取第一个和最后一个,中间的全部放入 a_list
first, *a_list, last = numbers
print(f"第一个: {first}")   # 输出: 第一个: 1
print(f"中间的列表: {a_list}") # 输出: 中间的列表: [2, 3, 4, 5]
print(f"最后一个: {last}")   # 输出: 最后一个: 6
1
2
3
4
5
6
7

# 4.3 解包的经典应用

  • 函数返回多个值
    def get_user_info():
        return "Alice", 25, "alice@example.com"
    
    name, age, email = get_user_info() # 优雅地接收返回值
    print(f"Name: {name}, Age: {age}, Email: {email}") # 输出: Name: Alice, Age: 25, Email: alice@example.com
    
    1
    2
    3
    4
    5
  • 优雅地交换变量
    a = 10
    b = 20
    a, b = b, a # 右侧创建了元组 (20, 10),然后解包给左侧的 a 和 b
    print(f"交换后: a={a}, b={b}") # 输出: 交换后: a=20, b=10
    
    1
    2
    3
    4
  • 在循环中同时获取索引和值
    fruits = ("apple", "banana", "cherry")
    for index, fruit in enumerate(fruits):
        print(f"索引 {index}: {fruit}")
    # 输出:
    # 索引 0: apple
    # 索引 1: banana
    # 索引 2: cherry
    
    1
    2
    3
    4
    5
    6
    7

# 5. “不可变”的深入理解

# 5.1 元组中的可变对象

这是一个高级但重要的概念:元组的“不可变”指的是元组本身所包含的元素的引用不可变,而不是元素对象自身的内容不可变。

如果一个元组中包含了可变对象(如列表),那么这个可变对象的内容是可以被修改的。

# 元组中包含一个列表
t = (1, 2, [3, 4])

# 尝试修改元组的直接元素会报错
# t[0] = 99  # 这会引发 TypeError: 'tuple' object does not support item assignment

# 但是,我们可以通过引用去修改元组内部列表的内容!
list_inside_tuple = t[2]
list_inside_tuple.append(5)

print(f"修改后的元组: {t}") # 输出: 修改后的元组: (1, 2, [3, 4, 5])
1
2
3
4
5
6
7
8
9
10
11

结论: 元组的不可变性提供的是“浅层”的保护。它保证了元组的结构(即它持有的直接引用)不会改变,但无法保证其内部可变元素的内容不被改变。


# 6. 元组的应用场景与优势

# 6.1 为什么要使用元组?

特性 元组 (Tuple) 列表 (List)
可变性 不可变 (Immutable) 可变 (Mutable)
性能 通常更快,占用内存更少 稍慢,占用内存更多
用途 数据保护、作为字典键、函数多值返回 存储需要频繁增删改的数据
语法 () 或省略 []

# 6.2 核心应用场景

  1. 作为函数返回多个值: 这是元组最常见的用途,代码简洁且高效。

  2. 作为字典的键: 因为元组是不可变的(可哈希的),所以它可以被用作字典的键。列表则不行。

    # 用坐标作为字典的键来存储城市信息
    locations = {
        (39.9042, 116.4074): "北京",
        (31.2304, 121.4737): "上海"
    }
    print(f"坐标(39.9042, 116.4074)的城市是: {locations[(39.9042, 116.4074)]}") 
    # 输出: 坐标(39.9042, 116.4074)的城市是: 北京
    
    1
    2
    3
    4
    5
    6
    7
  3. 保护数据不被意外修改: 当你有一组不希望在程序运行过程中被修改的数据(如配置信息、常量集、数据库记录)时,使用元组比列表更安全。


# 7. 进阶:命名元组 (namedtuple)

有时候,我们希望元组不仅能通过索引访问,还能像对象一样通过名称来访问其元素,以提高代码的可读性。这时 collections.namedtuple 就派上用场了。

namedtuple 是一个函数,它会创建一个自定义的元组子类。

from collections import namedtuple

# 1. 创建一个命名元组的 "模板"
Point = namedtuple('Point', ['x', 'y', 'z'])

# 2. 使用模板创建实例
p1 = Point(10, 20, 30)
p2 = Point(x=5, y=10, z=15)

# 3. 既能通过索引访问,也能通过名称访问
print(f"通过索引访问 p1 的 y: {p1[1]}")      # 输出: 通过索引访问 p1 的 y: 20
print(f"通过名称访问 p1 的 y: {p1.y}")      # 输出: 通过名称访问 p1 的 y: 20

print(f"p2 的 x, y, z 分别是: {p2.x}, {p2.y}, {p2.z}") # 输出: p2 的 x, y, z 分别是: 5, 10, 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14

命名元组兼具元组的高性能和不可变性,又提供了类似对象的可读性,是一种非常优雅的数据结构。

编辑此页 (opens new window)
上次更新: 2025/07/23, 06:33:16
列表
字典

← 列表 字典→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式