今天你 AI 赋能了吗?打开浏览器,在地址栏输入 xuefulu.ai ,按下 Enter 即可访问学府路1号!
2026年10月14日 星期三 10:40:19
常用网址: | | 学府路1号 https://xuefulu.ai | 下载 Python https://xuefulu.ai/Python.html | 下载 TRAE https://xuefulu.ai/Trae.html

一、一行给多个变量赋值

普通赋值是一个变量装一个值:

Python
a = 1
b = 2
c = 3

序列解包可以一行就给好几个变量同时赋值,只要右边是一串东西(列表、元组、字符串都行),左边用逗号隔开写变量名:

Python
a, b, c = 1, 2, 3
print(a, b, c)

输出:

输出
1 2 3

等号右边其实是被悄悄包成了一个元组 (1, 2, 3),再按位置一个个分给左边的变量。所以这句和下面这句效果一样:

Python
t = (1, 2, 3)
a, b, c = t
print(a, b, c)
序列解包最大的好处是让代码更直白:看到 a, b, c = ... 就知道「这一行在拆出三个值」,不用写三行赋值。

二、基本解包(列表/元组/字符串)

只要右边是「一串东西」,左边就能一次拆开。列表、元组、字符串都能解包。

① 列表解包

Python
numbers = [1, 2, 3]
a, b, c = numbers
print(f'a: {a}')
print(f'b: {b}')
print(f'c: {c}')

输出:

Python
a: 1
b: 2
c: 3

② 元组解包

Python
person = ('小明', 25, '工程师')
name, age, job = person
print(f'姓名: {name}')
print(f'年龄: {age}')
print(f'职业: {job}')

输出:

输出
姓名: 小明
年龄: 25
职业: 工程师

③ 字符串解包

Python
word = 'abc'
x, y, z = word
print(f'x: {x}')
print(f'y: {y}')
print(f'z: {z}')

输出:

Python
x: a
y: b
z: c
右边类型例子说明
列表a, b, c = [1, 2, 3]按位置拆成三个变量
元组a, b = (10, 20)和列表完全一样
字符串x, y, z = 'abc'每个字符当作一个元素
解包的本质是:左边变量个数 = 右边序列长度。记住这条,后面就顺了。

三、个数必须对上(两个真实 ValueError 原文)

解包时,左边变量个数必须和右边元素个数一模一样,多一个少一个都会报错。

① 右边多了(变量太少)

Python
a, b = [1, 2, 3]
报错
ValueError: too many values to unpack (expected 2)

② 右边少了(变量太多)

Python
a, b = [1]
报错
ValueError: not enough values to unpack (expected 2, got 1)

第一条说「想要 2 个值,但你给了 3 个」;第二条说「想要 2 个值,你只给了 1 个」。报错信息把你写错的个数都告诉你了,照着改就行。

如果元素个数不确定(比如用户想输入任意多个数),就别用等号左边写死个数,改用下一节的「星号解包」* 来收下多余的。
想先看看序列有几个元素?用 len():len([1,2,3]) 是 3。变量个数和它对齐就不会错。

课程思政|工匠精神与严谨求实 · 数目对不上,程序不答应

解包有条硬规矩:左边变量个数,必须和右边元素个数一模一样,多一个少一个都会报错。有意思的是,报错信息会直接告诉你「想要 2 个、你给了 3 个」,把差多少算得明明白白。对不上就是不对,程序从不将就。做统计也一样,账要对得上、数目要核得清,含糊过去的问题,迟早会回来找你。

四、星号解包(first, *rest、*head, last、a, *middle, b)

元素个数不确定时,用 * 把「剩下的一坨」打包给一个变量。* 拿到的一定是个列表。

① 只要第一个,其余都收下

Python
scores = [80, 90, 75, 85, 95]
first, *rest = scores
print(f'First score: {first}')
print(f'Rest scores: {rest}')

输出:

输出
First score: 80
Rest scores: [90, 75, 85, 95]

② 只要最后一个,前面都收下

Python
data = ('start', 1, 2, 3, 'end')
start, *middle, end = data
print(f'Start: {start}')
print(f'Middle: {middle}')
print(f'End: {end}')

输出:

Python
Start: start
Middle: [1, 2, 3]
End: end

③ 三个变量的完整写法

a, *middle, b:第一个给 a,最后一个给 b,中间所有给 middle。

Python
nums = [1, 2, 3, 4, 5]
head, *body, tail = nums
print(head, body, tail)

输出:

输出
1 [2, 3, 4] 5
写法含义星号变量得到
first, *rest = lst第一个单独拿,其余打包列表
*rest, last = lst最后一个单独拿,前面打包列表
a, *m, b = lst首尾单独拿,中间打包列表
一个赋值里只能有一个 *。写两个会直接报语法错:
Python
a, *b, c, *d = [1, 2, 3, 4, 5]
报错
SyntaxError: multiple starred expressions in assignment
记牢:* 永远给你一个列表,哪怕只剩一个元素也是 [x],不是单独的值。

五、交换变量

很多语言交换两个变量要借第三个「临时变量」,Python 用解包一行就搞定:

Python
x = 10
y = 20
x, y = y, x
print(f'x: {x}')
print(f'y: {y}')

输出:

Python
x: 20
y: 10

这句的右边 y, x 先组成一个元组 (20, 10),再解包给左边的 x, y。等价于「把 y 的值给 x,把 x 的值给 y」。

别写成 x = y; y = x(两行)。那样第二行 y = x 时,x 早就被改掉了,最后两个变量会相等,交换失败。
交换变量是解包最经典的「一行流」。考试或刷题时看到「不借助临时变量交换」,答案就是 x, y = y, x。

AI 助手小贴士|交换变量那行「魔法」值得追问到底。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:a, b = b, a 为什么不借助临时变量就能交换?右边到底先算了什么?再给 3 个星号解包的实用例子

六、函数返回多值就是解包

一个函数用 return 写多个值(用逗号隔开),返回的是一个元组。调用时用多个变量接住,就是解包:

Python
def get_point():
    return 3, 4

x, y = get_point()
print('坐标:', x, y)

输出:

输出
坐标: 3 4

再看一个实用的:函数同时返回最大值和最小值:

Python
def max_min(lst):
    return max(lst), min(lst)

big, small = max_min([8, 3, 12, 5])
print('最大:', big, '最小:', small)

输出:

输出
最大: 12 最小: 3
记住:函数「返回多个值」其实是返回一个元组。如果你只用一个变量接,拿到的是整个元组:p = get_point() 后 p 是 (3, 4)。
这一节提前出现了函数(def、return)——函数本身是第 22 篇《函数》的主题。现在只需要记住现象:返回多个值 = 拿到一个元组 = 解包接住,至于函数怎么写,到时候再说。

课程思政|诚信与职业操守 · 说返回一个值,其实是元组

函数用 return 写多个值,看着像返回了好几个,其实返回的是一个元组;只用一个变量接,拿到的就是整个元组。写函数的人把这层讲清楚,调用的人就不会猜错。接口不骗人,代码才靠得住。说清楚自己给的是什么、要的是什么,这是协作里最基本的诚实。

七、嵌套解包(for name, (age, job) in info)

当序列里还套着序列,解包也能一层层拆开。常用于「每条记录带好几个字段」的场景。

① 列表里套列表

Python
students = [('小明', [80, 90]), ('小红', [75, 85])]
for name, [score1, score2] in students:
    print(f'姓名: {name}')
    print(f'第一次: {score1}')
    print(f'第二次: {score2}')

输出:

输出
姓名: 小明
第一次: 80
第二次: 90
姓名: 小红
第一次: 75
第二次: 85

② 元组里套元组

Python
points = ((1, 2), (3, 4))
for (x, y) in points:
    print(f'x: {x}, y: {y}')

输出:

输出
x: 1, y: 2
x: 3, y: 4

③ 更复杂的嵌套

Python
info = [('小明', (25, '工程师')), ('小红', (30, '医生'))]
for name, (age, job) in info:
    print(f'姓名: {name}')
    print(f'年龄: {age}')
    print(f'职业: {job}')

输出:

输出
姓名: 小明
年龄: 25
职业: 工程师
姓名: 小红
年龄: 30
职业: 医生
嵌套解包就是「右边长什么样,左边就画一个一样的架子」。for name, (age, job) in ... 表示每条数据是一个「名字 + (年龄, 职业)」的结构。

八、解包还能这么用(for k, v in d.items()、print(*lst)、[*a, *b])

解包不止赋值,还能在好几个地方「展开」数据。

① 遍历字典:同时拿键和值

Python
d = {'x': 1, 'y': 2}
for k, v in d.items():
    print(k, v)

输出:

输出
x 1
y 2

② 用 * 把列表「打散」传给 print

Python
lst = [1, 2, 3]
print(*lst)

输出:

输出
1 2 3

*lst 把列表「拆开」成三个独立的参数传给 print,效果等同 print(1, 2, 3)。

③ 用 [*a, *b] 合并两个列表

Python
a = [1, 2]
b = [3, 4]
merged = [*a, *b]
print(merged)

输出:

输出
[1, 2, 3, 4]

④ 用 * 收集函数多余参数

Python
def add_all(*nums):
    total = 0
    for n in nums:
        total += n
    return total

print(add_all(1, 2, 3, 4))

输出:

输出
10
星号 * 在解包里有两个意思:放在赋值时(first, *rest = ...)是「收集剩余」;放在调用时(print(*lst))是「打散展开」。看位置就懂。

课程思政|科技自立自强 · 同一个星号,两种含义

星号 * 在解包里有两副面孔:写在赋值左边,是「把剩下的收成一个列表」;写在调用里,却是「把列表打散展开」。同一个符号两种用法,看位置就能分辨,这正是把语言的脾气摸透了。读懂设计者的用意,才谈得上用好它。等技术学到这一层,我们才有底气去改它、去造属于自己的工具。

九、十个基础案例

下面 10 个小案例都很短,建议每个都亲手敲一遍、跑一遍。

案例 1:一行记下三杯奶茶的价格

Python
a, b, c = 12, 15, 9
print(a, b, c)

输出:

输出
12 15 9

案例 2:拆出快递架上的「第几排第几列」

Python
rack = (3, 7)
row, col = rack
print('第', row, '排 第', col, '列')

输出:

输出
第 3 排 第 7 列

案例 3:取一周课表的首尾,中间打包

Python
week = ['周一', '周二', '周三', '周四', '周五']
first, *middle, last = week
print('开头:', first, '中间:', middle, '结尾:', last)

输出:

输出
开头: 周一 中间: ['周二', '周三', '周四'] 结尾: 周五

案例 4:交换两个人的奶茶口味

Python
m, n = '少冰', '常温'
m, n = n, m
print(m, n)

输出:

输出
常温 少冰

案例 5:函数一次返回歌名和歌手

Python
def song_info():
    return '晴天', '周杰伦'
name, singer = song_info()
print(name, singer)

输出:

输出
晴天 周杰伦

案例 6:遍历歌单,拆开每首的两个数据

Python
data = [('起风了', [88, 92]), ('晴天', [76, 85])]
for name, [p1, p2] in data:
    print(name, '平均', (p1 + p2) / 2)

输出:

输出
起风了 平均 90.0
晴天 平均 80.5

案例 7:遍历奶茶菜单的键值对

Python
price = {'珍珠奶茶': 12, '芝士葡萄': 18}
for name, p in price.items():
    print(name, '一杯', p, '元')

输出:

输出
珍珠奶茶 一杯 12 元
芝士葡萄 一杯 18 元

案例 8:取前两件快递,剩下的打包

Python
parcels = ['A1', 'B2', 'C3', 'D4', 'E5']
first, second, *others = parcels
print(first, second, others)

输出:

输出
A1 B2 ['C3', 'D4', 'E5']

案例 9:打散列表,打印宿舍床位

Python
beds = [7, 8, 9]
print('宿舍床位', *beds, '已分配')

输出:

输出
宿舍床位 7 8 9 已分配

案例 10:合并两份歌单

Python
a = ['晴天', '稻香']
b = ['起风了', '告白气球', '七里香']
c = [*a, *b]
print(c)

输出:

输出
['晴天', '稻香', '起风了', '告白气球', '七里香']

AI 助手小贴士|解包的实用性靠场景题来体会。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:出 3 道解包应用题:一行拆出名单的第一个和剩下的人、for 循环里同时拿下标和值、合并两个字典。给提示,先不给完整答案

十、常见坑

坑 1:左右个数对不上

Python
a, b = [1, 2, 3]     # 想拿 3 个却只写 2 个变量

报 ValueError: too many values to unpack (expected 2)。要么加变量,要么用 * 收下多余的。

坑 2:一个赋值写两个星号

Python
a, *b, *c = [1, 2, 3, 4]   # 两个星号,语法不允许

报 SyntaxError: multiple starred expressions in assignment。一个赋值只能有一个 *。

坑 3:忘了右边的「一串东西」

Python
a, b = 5     # 5 是单个数字,不是序列

报 TypeError: cannot unpack non-iterable int object。解包右边必须是可以一个一个取的序列(列表/元组/字符串等)。('int' object is not iterable 是 for x in 5 这类写法的报错,别混。)

坑 4:以为 * 拿到的是单个值

Python
first, *rest = [1, 2, 3]
print(rest + [4])      # rest 是列表,能直接相加

这里 rest 是 [2, 3](列表),不是 2。所以能和别的列表相加;想要里面第一个值要写 rest[0]。

解包和「普通多变量赋值」不一样:a = b = c = 0 是三个变量都指向同一个值;a, b, c = 0, 0, 0 才是分别赋三个值。别混了。
调试解包错误时,先 print(右边序列) 看一眼它到底有几个元素、长什么样,再决定左边写几个变量或用 *。

十一、报错手册

下面这些报错都是真跑出来的原文,照抄本机解释器。看到眼熟的,直接对照处理。

① 右边元素太多

Python
a, b = [1, 2, 3]
报错
ValueError: too many values to unpack (expected 2)

原因:左边 2 个变量,右边 3 个元素。加一个变量 c,或把第二个改成 *rest。

② 右边元素太少

Python
a, b = [1]
报错
ValueError: not enough values to unpack (expected 2, got 1)

原因:左边要 2 个,右边只有 1 个。检查序列是不是空的或被截断了。

③ 两个星号

Python
a, *b, c, *d = [1, 2, 3, 4, 5]
报错
SyntaxError: multiple starred expressions in assignment

原因:一个赋值只能有一个 *。拆成两次赋值,或只保留一个 *。

④ 右边不是序列

Python
a, b = 5
报错
TypeError: cannot unpack non-iterable int object

原因:5 是单个整数,不能解包。右边必须是列表、元组、字符串这类「可迭代」对象。

⑤ 解包一个空序列

Python
a, b = []
报错
ValueError: not enough values to unpack (expected 2, got 0)

原因:空序列一个元素都没有。先确认数据有没有被正确读进来。

⑥ 解包字典(默认只拿到键)

Python
d = {'x': 1, 'y': 2}
a, b = d
print(a, b)

输出:

输出
x y

这不是报错,但新手常以为能拿到值。直接解包字典只会拿到键;要拿键值对得写 for k, v in d.items():。

AI 助手小贴士|a, b = b, a 这行「魔法」值得让 AI 拆开讲——一行代码背后是完整的求值顺序。

打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:a, b = b, a 为什么不借助临时变量就能交换两个数?右边到底先算了什么?再给我 3 个序列解包的实用例子

十二、随堂自测(10 题)

点击选项即可判分,选错的题会立刻展开解析。做完可以看到正确率和错题清单,也可以重新答题。

已答 0 / 10 · 正确 0 —

1执行 a, b, c = 1, 2, 3 后,三个变量分别得到什么?

  • A. a=1, b=2, c=3
  • B. a=1, b=1, c=1
  • C. a=3, b=2, c=1
  • D. 报错,不能一次给三个变量赋值
答案:A。等号右边先组成元组 (1,2,3),再按位置解包给左边;这是最基础的「序列解包」,完全合法。

2a, b = [1, 2, 3] 会怎样?

  • A. 正常,a=1, b=2
  • B. 正常,a=1, b=[2,3]
  • C. 报 ValueError(个数对不上)
  • D. 报 TypeError
答案:C。左边 2 个变量、右边 3 个元素,个数不匹配会报 ValueError: too many values to unpack。想收下多余元素要用 a, *rest = ...。

3first, *rest = [80, 90, 75, 85, 95] 中,rest 是什么类型?

  • A. 一个单独的数字
  • B. 一个列表
  • C. 一个元组
  • D. 一个字符串
答案:B。带 * 的变量永远拿到一个列表,这里是 [90, 75, 85, 95],即使只剩一个元素也是列表。

4想交换两个变量 x 和 y 的值,最简洁的写法是?

  • A. x = y; y = x
  • B. temp = x; x = y; y = temp
  • C. x, y = y, x
  • D. swap(x, y)
答案:C。x, y = y, x 利用解包一行完成交换;Python 没有内置 swap 函数,两行写法会丢失原值。

5函数 def f(): return 3, 4,调用 a, b = f() 时发生了什么?

  • A. 返回的就是元组,被解包成 a=3, b=4
  • B. 只能用一个变量接,否则报错
  • C. a 和 b 都变成 (3,4)
  • D. 报 SyntaxError
答案:A。函数「返回多个值」其实是返回一个元组 (3,4),用多个变量接住就是解包。若只写 p = f(),p 才是整个元组。

6for k, v in d.items(): 遍历字典时,每次循环 k 和 v 分别是什么?

  • A. k 是值,v 是键
  • B. k 是键,v 是值
  • C. k 和 v 都是键
  • D. k 和 v 都是值
答案:B。d.items() 每次给出一个 (键, 值) 元组,解包后 k 拿到键、v 拿到值。这是遍历字典键值对的标准写法。

7下面哪个赋值会报语法错?

  • A. a, b = [1, 2]
  • B. a, *b = [1, 2]
  • C. a, *b, c = [1, 2, 3]
  • D. a, *b, *c = [1, 2, 3, 4]
答案:D。一个赋值里只能有一个 *,写两个会报 SyntaxError: multiple starred expressions。其余三种都合法。

8x, y, z = 'abc' 执行后,y 的值是?

  • A. 'abc'
  • B. 97(字符 b 的编码)
  • C. 'b'
  • D. 报错,字符串不能解包
答案:C。字符串也是序列,会按字符一个个解包,x='a'、y='b'、z='c'。

9直接写 a, b = {'x': 1, 'y': 2}(不解包 items),a 和 b 拿到的是什么?

  • A. 两个值 1 和 2
  • B. 两个键 'x' 和 'y'
  • C. 整个字典
  • D. 报错
答案:B。直接解包字典只拿到键,不会拿到值。想同时拿键值对要写 for k, v in d.items():。

10print(*[1, 2, 3]) 和 print([1, 2, 3]) 的输出区别是?

  • A. 完全一样
  • B. 前者报错
  • C. 后者报错
  • D. 前者打出 1 2 3,后者打出 [1, 2, 3]
答案:D。*lst 在调用时把列表「打散」成独立参数,所以 print(*[1,2,3]) 输出 1 2 3;不加星号则把整个列表当一个参数,输出带方括号。