Python 现代开发学习笔记

(九)元组、同时赋值与拆包

1. 用元组把几个值放在一起

把“书名与分钟数”看作一条记录,可以使用元组:

# 逗号把两个值组织成元组,括号使结构更清楚。
record = ("Python", 45)
print(record[0], record[1])
# 一个元素的元组也需要逗号;只有括号仍只是原来的值。
print(type((45,)), type((45)))

元组保持顺序,支持下标和切片,但不能把 record[0] 替换成另一个值。它内部若引用可变对象,被引用对象仍然可以改变,例如 ([1],) 里保存的列表可以追加元素。元组固定的是它保存的各个引用位置。

2. 多个名字接收多个值

# 右边先得到 1 和 2,再按位置绑定 a 与 b。
a, b = 1, 2
print(a, b)
# 读取右边时仍是旧的 a、b,随后再分别更新左边。
a, b = b, a
print(a, b)

输出 1 2 和 2 1。右边的逗号把结果组成一组,左边的逗号把接收位置拆开。这种把多个值分配给多个目标的动作叫拆包。

同时赋值与交换中的右侧求值

交换时先保留右边的旧值 (2, 1),再更新左边。若展开成 a = b,接着 b = a,第二行读到的已经是新的 a,两者会都变成旧的 b。

3. 拆开已有数据与嵌套结构

# 元组、列表与字符串都能按迭代顺序提供拆包的数据。
title, minutes = ("Python", 45)
x, y = [10, 20]
first, second = "书架"
print(title, minutes, x, y, first, second)
# 左边的形状继续对应右边的内部结构。
name, (read, total) = ("小林", (3, 8))
print(name, read, total)

普通拆包按接收位置取出相应数量的项,再完成名称绑定。写 a, b = [1, 2, 3] 会报 ValueError:右边多出了一项,左边没有接收位置。需要保存中间任意多项时,用星号目标:

# 开头和结尾分别接收一项,中间余下的项收集成列表。
first, *middle, last = [10, 20, 30, 40]
print(first, middle, last)
# 没有中间项时,星号目标得到空列表。
left, *rest, right = [10, 40]
print(left, rest, right)

输出 10 [20, 30] 40 和 10 [] 40。星号目标最终得到列表,不会把中间多项压成一个数字。

星号拆包的元素分配

不关心某个值时常用 _ 接收,例如 title, _ = ("Python", 45)。_ 在这里是普通名称,只是表达“不打算继续用这个结果”的习惯,不会让 Python 跳过产生该值的动作。

4. 链式赋值与分别创建对象

# 右边只创建一次空列表,a 与 b 共同指向它。
a = b = []
a.append(1)
print(a, b)
# 右边两个列表表达式分别创建对象,再拆包绑定。
a, b = [], []
a.append(1)
print(a, b)

两行输出分别是 [1] [1] 和 [1] []。多个等号让多个目标接收同一个右侧结果,逗号拆包则从右侧的一组结果里依次接收对象。把“右边创建了几个对象”和“左边有哪些名称”分开看,就能解释共享发生在哪里。

笔记正文与全部题解 · Ctrl / ⌘ K