有关Python解包的终极指南

618 阅读6分钟

在这篇文章中,你将了解到以下主题:

  • 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 下面是一个例子,我们在一个变量23 中捕获两个元素,在*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
[]
'''