序列解包
序列解包是 Python 中将可迭代对象的元素批量赋值给多个变量的语法特性。
基本解包
当赋值号左侧是逗号分隔的变量列表时,Python 自动将右侧元素依次拆给这些变量:
t = (12345, 54321, 'hello!')
x, y, z = t
print(x) # 12345
任何序列或可迭代对象都支持解包:
a, b, c = [1, 2, 3]
first, second, third = "abc"
x, y, z = range(3)
左侧变量数与右侧元素数必须严格相等,否则会报错:
a, b = [1, 2, 3] # ValueError: too many values to unpack
扩展解包:星号 *
Python 3 允许用 *变量 收集"剩余"元素:
first, *rest = [1, 2, 3, 4, 5] # first=1, rest=[2,3,4,5]
*rest, last = [1, 2, 3, 4, 5] # rest=[1,2,3,4], last=5
first, *middle, last = [1, 2, 3, 4, 5] # 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
matrix = [[1, 2], [3, 4]]
(a, b), (c, d) = matrix
print(a, b, c, d) # 1 2 3 4
解包在赋值中的应用
不借助临时变量交换两个值:
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
拆分复合返回值:
def get_min_max(nums):
return min(nums), max(nums)
minimum, maximum = get_min_max([3, 1, 4, 1, 5])
解包在循环中的应用
for 循环的迭代变量支持解包:
# 遍历字典项
for k, v in {'a': 1, 'b': 2}.items():
print(k, v)
# 遍历枚举
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v)
# 遍历 zip 结果
for q, a in zip(['name', 'quest'], ['lancelot', 'holy grail']):
print(q, a)
扩展解包处理长度不定的序列:
records = [('foo', 1, 2), ('bar', 'hello'), ('baz', 3, 4, 5)]
for tag, *args in records:
print(tag, args)
解包在函数参数中的应用
调用函数时,* 将序列展开为位置参数,** 将字典展开为关键字参数:
def greet(name, dept, salary):
print(f"{name} from {dept}, salary {salary}")
info = ["Alice", "Engineering", 80000]
greet(*info) # 等价于 greet("Alice", "Engineering", 80000)
emp = {"name": "Bob", "dept": "Sales", "salary": 70000}
greet(**emp) # 等价于 greet(name="Bob", dept="Sales", salary=70000)
* 和 ** 可以混合使用,但顺序必须是位置参数在前,关键字参数在后:
def func(a, b, c, d=0, e=0):
print(a, b, c, d, e)
func(*[1, 2], 3, **{"d": 4, "e": 5}) # 1 2 3 4 5
边界情况
解包空序列时,非星号变量必须能匹配到值:
a, *b = [] # ValueError: not enough values to unpack
*a, = [1, 2, 3] # ✅ a = [1, 2, 3]
右侧必须支持迭代:
a, b = 10 # TypeError: cannot unpack non-iterable int object