飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

元组

元组(tuple)是 Python 的核心序列类型之一,与列表共享索引、切片、迭代等操作,但具有不可变性(immutable)。这种不可变性使元组在特定场景下比列表更安全、更高效,也使其能够作为字典的键或集合的元素。

创建元组

元组由逗号分隔的值组成,圆括号在大多数情况下只是可选的分组符号:

t = 12345, 54321, 'hello!'   # 合法,圆括号可省略
print(t)                      # (12345, 54321, 'hello!')
print(t[0])                   # 12345

当元组作为更大表达式的一部分时,圆括号变得必要,否则逗号会被解析为参数或运算符分隔符:

# 作为函数参数的一部分
len((1, 2, 3))    # 圆括号区分元组与多个参数

# 元组嵌套
u = t, (1, 2, 3, 4, 5)
print(u)          # ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))

空元组用一对空圆括号创建:empty = ()。单元素元组是创建时的常见陷阱——必须在元素后加逗号,否则圆括号会被当作分组运算符:

singleton = 'hello',     # ✅ 元组,注意末尾逗号
print(len(singleton))     # 1
print(singleton)          # ('hello',)

not_tuple = ('hello')     # ❌ 只是字符串 'hello'
print(type(not_tuple))    # <class 'str'>

末尾逗号在输出时也会显示,这是 Python 区分单元素元组与分组表达式的语法标记。

不可变性

元组一旦创建,就不能通过索引赋值、切片赋值或任何方法修改其结构:

t = (1, 2, 3)
t[0] = 99     # TypeError: 'tuple' object does not support item assignment
del t[0]      # TypeError: 'tuple' object doesn't support item deletion

但不可变性只作用于元组容器的结构,不限制其内部可变对象的内容。如果元组包含列表、字典等可变对象,这些对象的内容仍可修改:

v = ([1, 2, 3], [3, 2, 1])
v[0][0] = 99
print(v)      # ([99, 2, 3], [3, 2, 1])

这种"浅不可变"特性意味着,包含可变对象的元组不能安全地作为字典键或集合元素,因为其等效性可能在创建后改变,破坏哈希容器的内部一致性。

元组与列表的使用场景有明确分野:列表适合同质元素的动态集合,需要频繁增删;元组适合异质数据的固定记录,作为不可变标识或轻量结构体使用。

元组解包

元组支持序列解包(sequence unpacking),将右侧元组的元素依次赋给左侧变量:

t = (12345, 54321, 'hello!')
x, y, z = t
print(x)   # 12345
print(y)   # 54321
print(z)   # hello!

解包要求左侧变量数与右侧元素数严格匹配,否则会报错:

a, b = (1, 2, 3)     # ValueError: too many values to unpack
a, b, c, d = (1, 2)  # ValueError: not enough values to unpack

扩展解包使用星号 * 收集剩余元素,解决数量不匹配的问题:

first, *rest = (1, 2, 3, 4)
print(first)   # 1
print(rest)    # [2, 3, 4],注意结果是列表

*rest, last = (1, 2, 3, 4)
print(rest)    # [1, 2, 3]
print(last)    # 4

first, *middle, last = (1, 2, 3, 4, 5)
print(middle)  # [2, 3, 4]

星号变量收集的结果永远是列表,即使只有一个元素或没有元素:

a, *b = (1,)       # a=1, b=[]
a, *b, c = (1, 2)  # a=1, b=[], c=2

嵌套元组也支持嵌套解包:

data = ("Alice", (25, "Engineer"))
name, (age, job) = data
print(age)   # 25
print(job)   # Engineer

命名元组

标准库 collections 模块提供的 namedtuple() 工厂函数,可以创建带字段名的元组子类。命名元组兼具元组的不可变性和类的可读性:

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(11, y=22)

print(p.x)        # 11,字段名访问
print(p[0])       # 11,索引访问依然有效
print(p.y)        # 22

命名元组与普通元组完全兼容,支持解包、索引、迭代,同时提供自文档化的字段名。对于简单数据记录,命名元组比完整类定义更轻量:

Employee = namedtuple('Employee', 'name dept salary')
emp = Employee('Alice', 'Engineering', 80000)

# 解包
name, dept, salary = emp

# 转换为字典
emp_dict = emp._asdict()
# {'name': 'Alice', 'dept': 'Engineering', 'salary': 80000}

# 替换字段创建新实例(元组不可变,返回新对象)
emp2 = emp._replace(salary=90000)

Python 3.7+ 中,如果不需要与旧版本兼容,数据类(@dataclass)提供了更强大的替代方案;但在需要不可变性、哈希性或最小内存开销的场景下,命名元组仍是优秀选择。

上一页
列表推导式
下一页
序列解包