在这篇文章中,你将了解到以下主题:
- Python中的列表解包
- Python中的元组解包
- Python中的字符串解包
- ValueError: 太多的值需要解包 (预计是k)
- ValueError: 没有足够的值来解包 (预期 x, 得到 y)
- 解压嵌套的列表或元组
- 解压下划线
- 解压星号
序列解包基础知识
Python 允许你分配迭代变量,如列表和元组,并将它们分配给多个变量。
迭代器解包或 序列解包是将一个可迭代的元素(例如,元组、列表、字符串)分配给多个变量的过程。为了使其发挥作用,你需要有足够的变量来捕捉可迭代的元素数量。
Python 列表解包
列表解包是在一行代码中把一个列表的k个元素分配给k 个不同的变量的过程。
在下面的例子中,你将列表[1, 2, 3] 中的三个元素解包到变量a,b, 和c 中。每个变量在解包操作后捕获了一个列表元素。
# List Unpacking
a, b, c = [1, 2, 3]
print(a)
# 1
print(b)
# 2
print(c)
# 3
ValueError: 太多的值需要解包 (预计是k)
如果列表中有太多的值需要解包,也就是说,列表中元素的数量大于要把它们赋值给的变量,Python 将引发一个ValueError: too many values to unpack (expected k) ,而 k 是赋值操作左边的变量数量。
这可以在下面的代码片段中看到。
a, b, c = [1, 2, 3, 4]
'''
Traceback (most recent call last):
File "C:\Users\xcent\Desktop\code.py", line 1, in <module>
a, b, c = [1, 2, 3, 4]
ValueError: too many values to unpack (expected 3)
'''
为了解决ValueError: too many values to unpack (expected k) ,要确保解包操作的左右两边的元素数量是一样的。
根据惯例,如果你不需要在变量中存储某个列表元素,你可以使用 "丢弃 "的下划线变量名_ 。
下面是使用下划线名称解决的同一个例子。
a, b, _, c = [1, 2, 3, 4]
print(a)
# 1
print(b)
# 2
print(c)
# 4
ValueError: 没有足够的值来解包(预期x,得到y)。
如果迭代器中有太少的值可以解包--即迭代器中的元素数大于要把它们赋值给的变量数--Python 将引发一个ValueError: not enough values to unpack (expected x, got y) ,而x 是赋值操作左侧的变量数,y 是迭代器中的元素数。
这可以在下面的代码片段中看到。
a, b, c, d = [1, 2, 3]
'''
Traceback (most recent call last):
File "C:\Users\xcent\Desktop\code.py", line 1, in <module>
a, b, c, d = [1, 2, 3]
ValueError: not enough values to unpack (expected 4, got 3)
'''
为了解决 `ValueError: not enough values to unpack (expected x, got y)`,要确保解包操作的右边和左边的元素数量是相同的。
Python元组解包
元组解包是在一行代码中把一个元组的k个元素分配给k个不同的变量的过程。
在下面的例子中,你将元组(1, 2, 3) 中的三个元素解包到变量a,b, 和c 中。每个变量在解包操作后捕获了一个元组元素。
# Tuple Unpacking
a, b, c = (1, 2, 3)
print(a)
# 1
print(b)
# 2
print(c)
# 3
注意元组的括号是可选的,所以你可以省略它们,以更少的语法开销获得同样的行为,如下例所示。
# Tuple Unpacking
a, b, c = 1, 2, 3
print(a)
# 1
print(b)
# 2
print(c)
# 3
Python 字符串解包
字符串解包是在一行代码中把一个字符串的k个字符分配给k个不同的变量的过程。
在下面的例子中,你将字符串'finxter' 中的七个字符解压到变量a,b,c,d,e,f, 和g 。在解包操作之后,每个变量从字符串中依次捕获一个字符。
# String Unpacking
a, b, c, d, e, f, g = 'finxter'
print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
'''
f
i
n
x
t
e
r
'''
Python 解压缩嵌套的列表或元组
你也可以解压一个嵌套的迭代器 (例如,列表的列表,或元组的元组)。
简单的情况是,一个变量 (在我们的例子中是c) 捕获整个内部列表 (在我们的例子中是[3, 4, 5])。
lst = [1, 2, [3, 4, 5]]
a, b, c = lst
print(a)
print(b)
print(c)
'''
1
2
[3, 4, 5]
'''
但是如何将内层列表的元素也分配给变量呢?
这可以通过使用小括号(...) 或方括号[...] ,在方程的左右两边设置一个平行结构来实现。
lst = [1, 2, [3, 4, 5]]
a, b, [c, d, e] = lst
print(a)
print(b)
print(c)
print(d)
print(e)
'''
1
2
3
4
5
'''
Python解包下划线
Python中的下划线_ ,其行为与普通的变量名一样。按照惯例,如果你实际上并不关心存储在其中的值,而只是用它以语法正确的方式从一个迭代器中捕获所有的值,就可以使用它。
这里有一个简单的例子。
lst = ['Alice', 'Bob', 'Carl']
a, _, c = lst
print(a)
print(_)
print(c)
'''
Alice
Bob
Carl
'''
Python解包星号
你可以在等式的左边使用星号运算符*,将多个元素解包到一个变量中。
这样,你就可以克服ValueError: too many values to unpack ,当有 迭代器中的值多于变量的数量来捕获它们。
b 下面是一个例子,我们在一个变量2 和3 中捕获两个元素,在*b 中使用星号运算符作为前缀。
a, *b, c = [1, 2, 3, 4]
print(a)
print(b)
print(c)
'''
1
[2, 3]
4
'''
Python 将自动把迭代器中的值分配给变量,这样星号'变量就能捕获所有剩余的元素。
在下面的例子中,带星号的变量*a 捕获了所有不能被非星号的变量捕获的剩余值。
*a, b, c = [1, 2, 3, 4, 5]
print(a)
print(b)
print(c)
'''
[1, 2, 3]
4
5
'''
无论星号变量捕获多少元素,它们都将被存储为一个列表(即使一个变量就足够了)。
first, *_, last = ['Alice', 'Bob', 'Carl']
print(first)
print(_)
print(last)
'''
Alice
['Bob']
Carl
'''
然而,你不能在同一个表达式中使用多个星号运算符,否则 Python 将不知道哪些可迭代的元素要分配给哪些变量。
下面的截图显示了Python不编译时的警告情况 "SyntaxError: 赋值中的多个星号表达式".

如果你对一个大列表中除了几个元素以外的所有元素完全不感兴趣,你可以把扔掉的下划线运算符_ 和星号运算符* 结合起来,像这样*_ 。使用这种方法,下划线将从迭代器中捕获所有不必要的元素。
这可以在下面的例子中看到。
如何在变量中捕获迭代器的第一个和最后一个元素 [例] 。
下面是一个例子。
first, *_, last = list(range(100))
print(first, last)
# 0 99
所有的 list 元素 1 到 98 (包括在内) 现在都存储在丢弃的变量中_ 。
如果没有额外的元素可以分配给它,因为所有的元素都已经分配给其他变量,Python 将一个空列表分配给带星号的变量。
a, b, *c = [1, 2]
print(a)
print(b)
print(c)
'''
1
2
[]
'''