解包(Unpacking)是 Python 中最实用的语法糖之一。它能显著减少临时变量和循环,让代码更紧凑、更接近数学表达。
我们用一个经典问题开场:读入三个整数并排序,然后按给定的字母顺序输出。
1values = sorted(map(int, input().split()))
2order = input()
3
4named = {"A": values[0], "B": values[1], "C": values[2]}
5
6print(*(named[ch] for ch in order), end="")
这里的 *(named[ch] for ch in order) 就是解包操作:把生成器产生的多个值展开成 print 的独立参数,等价于 print(5, 1, 3)。
下面我们把解包的所有实用场景梳理一遍。
1. * 解包:展开可迭代对象
函数调用时解包
1print(*[1, 2, 3]) # 等价于 print(1, 2, 3)
2print(*range(5)) # 0 1 2 3 4
3
4# 数学函数
5nums = [3, 1, 4, 1, 5]
6print(max(*nums)) # 5
7# 但 max 本身支持可迭代对象,所以 max(nums) 更直接
合并多个列表
1a = [1, 2]
2b = [3, 4]
3merged = [*a, *b] # [1, 2, 3, 4]
等价于 a + b,但在函数返回时或表达式中间组合时非常方便。
赋值时的扩展解包
把可迭代对象的一部分拆给变量,剩余的部分用 * 接收。
1first, *rest = [1, 2, 3, 4]
2# first = 1, rest = [2, 3, 4]
3
4*begin, last = [1, 2, 3, 4]
5# begin = [1, 2, 3], last = 4
6
7first, *middle, last = [1, 2, 3, 4]
8# first = 1, middle = [2, 3], last = 4
9
10# 竞赛中的实用场景:读入 n 和数组
11n, *a = map(int, input().split())
12# 输入 "5 1 2 3 4 5" → n=5, a=[1,2,3,4,5]
矩阵转置:zip(*matrix)
这是竞赛中的高频技巧。
1matrix = [[1, 2, 3],
2 [4, 5, 6]]
3
4# 转置
5transposed = list(zip(*matrix))
6# [(1, 4), (2, 5), (3, 6)]
zip(*matrix) 等价于 zip([1,2,3], [4,5,6]),把每行的对应列元素配对。
用 * 清空列表
1*a, = range(5)
2# a = [0, 1, 2, 3, 4]
注意后面的逗号,这是语法要求。
2. ** 解包:展开字典
合并字典
1d1 = {"a": 1, "b": 2}
2d2 = {"c": 3, "d": 4}
3
4merged = {**d1, **d2}
5# {'a': 1, 'b': 2, 'c': 3, 'd': 4}
6
7# 后面的覆盖前面的 key
8d1 = {"a": 1, "b": 2}
9d2 = {"b": 99, "c": 3}
10merged = {**d1, **d2}
11# {'a': 1, 'b': 99, 'c': 3}
更新字典的简洁写法
1base = {"x": 0, "y": 0}
2point = {**base, "y": 5} # 更新 y,保留 x
3# {'x': 0, 'y': 5}
等价于 base.copy(); base["y"] = 5 但在一行内完成。
函数调用时解包字典
1def draw_point(x, y, color="black"):
2 print(f"({x}, {y}) in {color}")
3
4params = {"x": 10, "y": 20, "color": "red"}
5draw_point(**params) # (10, 20) in red
3. 综合实战
读入矩阵并转置
1n, m = map(int, input().split())
2matrix = [list(map(int, input().split())) for _ in range(n)]
3
4col_sum = [sum(col) for col in zip(*matrix)] # 每列的和
从字典构建格式化输出
1data = {"A": 5, "B": 3, "C": 1}
2order = "CAB"
3print(*(data[ch] for ch in order))
4# 1 5 3
拆分并合并区间
1l1, r1 = map(int, input().split())
2l2, r2 = map(int, input().split())
3
4# 取并集的端点
5left = min(l1, l2)
6right = max(r1, r2)
总结
| 写法 | 作用 | 竞赛场景 |
|---|---|---|
*iterable | 展开可迭代对象为函数参数 | print(*arr) |
zip(*matrix) | 矩阵转置 | 行列互换 |
a, *b = iterable | 扩展解包赋值 | 分出第一个和剩余 |
{**d1, **d2} | 合并字典 | 合并配置 |
f(**d) | 字典解包为关键字参数 | 参数转发 |
解包的核心思想是:不要手动写循环去拆解结构,让 Python 帮你拆。