Python 中的参数打包和解包

2024 年 08 月 29 日 | 阅读 9 分钟

在本教程中,我们将学习参数的打包和解包。Python 提供了一种独特的特性来打包或解包参数。假设我们有一个需要五个参数的函数;我们创建一个包含五个元素的列表并将其传递给函数,这会引发错误,因为元素被打包在列表中。我们需要向函数传递五个单独的参数。

过去,Python 开发者将此特性称为元组解包,但它变得非常有用且流行。因此,此特性已推广到所有可迭代对象;如今,它被称为可迭代对象解包。

我们将讨论如何使用可迭代对象解包来使我们的代码更具可读性。

此外,我们还将探讨一些实际的循环、函数定义和函数调用的示例。

Python 中的打包与解包

Python 提供了在赋值操作的左侧声明变量的功能。这些变量可以与右侧可迭代对象中的元组元素数量相同。每个变量都可以从右侧可迭代对象中获得一个值(如果使用 * 运算符,则可以获得更多值)。Python 开发者将此过程称为元组解包。以下是打包和解包参数的定义。

打包 - 顾名思义,它将所有参数包装到一个变量中,并且此函数调用会进入一个名为 args 的元组。我们可以使用除 args 之外的任何其他名称。

  • 示例: def func( *args )

解包 - 解包是指将列表或元组分配给单个变量的操作。

  • 示例 - (a, b, c) = List/tuple

解包使代码更具可读性,因此在 Python 开发者中广受欢迎。让我们通过一个例子来理解解包在 Python 中的工作原理。

解包元组

Python 允许我们将赋值运算符左侧的元组变量与右侧的元组值进行分配。如果变量数量与元组值的数量相同,则值将根据其在左侧的位置自动分配给左侧。让我们理解下面的例子。

示例 -

输出

1
2
3
4
5
6

正如我们所见,我们在赋值运算符的两侧都放置了元组。元组的值根据它们相对位置分配给变量。例如,a 将是 1,b 将是 2,依此类推。

我们不需要在两侧都创建元组;我们可以简单地使用以下方式。

示例 -

注意 - 左侧变量的数量必须等于赋值运算符右侧元组的元素数量。否则,将引发 ValueError。

在下面的示例中,我们在左侧使用四个变量,在右侧使用五个值。由于值太多无法解包,它将引发 ValueError。

示例 -

输出

ValueError: too many values to unpack (expected 4)

解包可迭代对象

元组解包操作已扩展到 Python 的其他可迭代对象。唯一的要求是,项在接收的元组(或列表中)中为每个变量产生相同的项。

让我们理解以下示例 -

示例 -

输出

1
2
3
Unpacking lists
1
2
3
Unpacking generators
0
1
4
Unpacking dictionaries (keys, values, and items
one
two
three
Unpack values
1
2
3
Unpacking key-value pairs
('one', 1)
('two', 2)
('three', 3)

另一方面,我们可以使用以下方式解包参数,其中列表/元组定义在赋值运算符的左侧,值在右侧。

示例 -

输出

1
2
3

但是,在实际代码中不建议这样做,因为它可能对初学者 Python 开发者来说有点令人困惑。

我们也可以使用集合解包操作,因为集合是无序集合。因此,赋值顺序可能会导致细微的错误。让我们理解下面的例子。

示例 -

输出

y
z
x

集合返回无序元素,因此解包参数也会如此。因此,建议避免使用集合解包操作。

使用 * 运算符进行打包

* 运算符是元组(或可迭代对象)解包运算符。它允许将多个值打包到一个变量中。我们在下面的示例中使用 * 运算符将元组值打包到一个变量中。

示例 -

输出

['x', 'y', 'z']

赋值的左侧必须是元组(或列表)。这就是我们使用尾随逗号的原因。

让我们看看另一种打包参数的方法。

示例 -

输出

1
2
['x', 'y', 'z']

在上面的代码中,我们将剩余的值打包到 b 中。

输出

[1]
2
3

在 a 中打包零个值(a 默认为 []),因为 b、c 和 d 是必需的。

示例 -

输出

[]
1
2
3

如果不对必需变量传递值,则会引发错误。

示例 -

输出

ValueError: not enough values to unpack (expected at least 4, got 3)

当我们要访问生成器中的元素而无需使用 list() 函数时,使用 * 运算符将值打包到单个变量中会非常方便。让我们理解下面的例子。

示例 -

输出

 at 0x7fcc4aec0ac0>
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

解释 -

在上面的代码中,我们将元素打包到 gen 中,并将生成器分别放入 g 和 r 中。使用此方法,我们可以省略 list() 函数来从 range 对象创建值列表。

打包和解包的同步工作

我们已经分别讨论了打包和解包,现在我们将把这两个概念付诸实践。打包和解包允许程序员编写更具可读性、清晰且符合 Python 风格的代码。让我们看一些打包和解包的例子。

并行赋值

并行赋值是 Python 中解包最常见的用例。如前所述,我们可以根据可迭代对象(元组或列表)为多个变量赋值。

让我们理解下面的例子。

示例 -

输出

The name is:  Mathew Wade
The age is:  400000$
The profile is:  Software Engineer

上面的代码相当传统且笨拙,难以输入。我们可以将其变得更容易和更具可读性,如下所示。

示例 -

输出

The name is:  Mathew Wade
The age is:  400000$
The profile is:  Software Engineer

正如我们所见,通过使用解包,我们减少了行数,使其变得简单而优雅。

交换变量之间的值

我们可以在 Python 中交换值,而无需使用临时变量或辅助变量。让我们理解下面的交换示例。

示例 - 不交换

输出

10
10
10

示例 -

输出

200
100

在语句 a, b = b, a 中,我们在一行代码中将 a 重新分配给 b,将 b 重新分配给 a。它更具可读性且更直接。另外,请注意,使用这种技术,无需新的临时变量。

使用 * 删除不必要的值

我们可以使用 * 来删除不需要的值。让我们理解下面的例子。

示例 -

输出

6
8

函数中返回元组

我们可以从 Python 函数中返回用逗号分隔的多个值。由于我们可以定义不使用括号的元组对象,因此此类操作可以解释为返回值的元组。如果编写返回多个值的函数,则可以对返回的值执行可迭代对象打包和解包操作。

让我们理解下面的例子。

示例 -

输出

(8, 64, 512)
8
64
512
8

使用 * 运算符合并可迭代对象

解包运算符 * 的另一个有趣用例是能够将多个可迭代对象合并为一个最终序列。此功能适用于列表、元组和集合。请看以下示例

示例 -

输出

(0, 1, 2, 3, 4)
[0, 1, 2, 3, 4]
{0, 1, 2, 3, 4}
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, '1', '2', '3']

在定义序列时,我们可以使用可迭代对象解包运算符 * 将子序列(或可迭代对象)的元素解包到最终序列中。它将允许我们使用现有序列即时创建序列,而无需调用 append() 和 insert() 等方法。

使用 * 运算符解包字典

Python 提供 ** 运算符来解包字典。此运算符也称为字典解包运算符。此运算符的使用由 PEP 448 扩展。现在,我们可以在函数调用和列表推导式中使用它。

示例 -

输出

{'one': 1, 'two': 2, 'three': 3, 'a': 'Apple', 'b': 'Bat', 'c': 'Cat'}

解释 -

在上面的代码中,我们创建了两个字典;我们解包了这两个字典并创建了一个组合的新字典,其中包含这两个字典的元素。

解包 for 循环

我们也可以在 for 循环的上下文中进行可迭代对象解包。当运行 for 循环时,循环在每次迭代中将可迭代对象的一个项分配给目标变量。如果要分配的项目是可迭代对象,则可以使用目标变量的元组。

让我们理解以下示例 -

示例 -

输出

Marks of Mathew is: 135
Marks of Warner is: 155
Marks of Kapil is: 175

结论

可迭代对象解包是 Python 中一项重要且非常有用的功能。此功能允许我们将可迭代对象解包到多个变量中。在本教程中,我们讨论了可迭代对象解包和打包的一些关键概念。我们已经看到了一些有价值的示例以及如何编写更具可读性、可维护性且符合 Python 风格的代码。

这些知识可以解决常见问题,例如并行赋值和交换变量之间的值。我们还可以在循环等其他 Python 概念中使用此功能。