Python has a built-in tuple type that can be used to create immutable, ordered sequences of values. In the simplest case, a tuple is a pair of two values, such as keys and values from a dictionary:
Python有一个内置的元组类型,可以用来创建不可变的、有序的值序列。在最简单的情况下,元组是一对值,比如字典的键值对:
snack_calories = {
'chips ': 140,
'popcorn ': 80,
'nuts ': 190,
}
items = tuple (snack_calories.items ())
print (items)
>>>
( ( 'chips ', 140), ( 'popcorn ', 80), ( 'nuts ', 190))
The values in tuples can be accessed through numerical indexes:
元组中的值可以通过数值索引访问:
item = ( 'Peanut butter ', 'Jelly ')
first = item[0]
second = item[1]
print (first, 'and ', second)
>>>
Peanut butter and Jelly
Once a tuple is created, you can’t modify it by assigning a new value to an index:
一旦元组被创建,你就不能通过给索引赋新值来修改它:
pair = ( 'Chocolate ', 'Peanut butter ')
pair [0] = 'Honey '
>>>
Traceback ...
TypeError: 'tuple ' object does not support item assignment
Python also has syntax for unpacking, which allows for assigning multiple values in a single statement. The patterns that you specify in unpacking assignments look a lot like trying to mutate tuples—which isn’t allowed— but they actually work quite differently. For example, if you know that a tuple is a pair, instead of using indexes to access its values, you can assign it to a tuple of two variable names:
Python的解包语法,允许它在一条语句中给多个变量同时赋值。解包赋值的模式看起来很像试图改变元组(这是不允许的),但它们实际上的运行原理非常不同。例如,如果你知道一个元组是一对,你可以将它赋值给两个变量名,而不是使用索引来访问它的值:
item = ( 'Peanut butter ', 'Jelly ')
first, second = item # Unpacking
print (first, 'and ', second)
>>>
Peanut butter and Jelly
Unpacking has less visual noise than accessing the tuple’s indexes, and it often requires fewer lines. The same pattern matching syntax of unpacking works when assigning to lists, sequences, and multiple levels of arbitrary iterables within iterables. I don’t recommend doing the following in your code, but it’s important to know that it’s possible and how it works:
解包比访问元组的索引具有更少的视觉干扰,而且通常需要更少的行。当给列表、序列和可迭代对象中任意级别的可迭代对象赋值时,解包的匹配语法模式也同样适用。我不建议在你的代码中做以下事情,但重要的是你要知道这是可能的,以及它是如何工作的:
favorite_snacks = {
'salty ': ( 'pretzels ', 100),
'sweet ': ( 'cookies ', 180),
'veggie ': ( 'carrots ', 20),
}
( (type1, (name1, cals1)),
(type2, (name2, cals2)),
(type3, (name3, cals3))) = favorite_snacks.items ()
print (f 'Favorite {type1} is {name1} with {cals1} calories ')
print (f 'Favorite {type2} is {name2} with {cals2} calories ')
print (f 'Favorite {type3} is {name3} with {cals3} calories ')
>>>
Favorite salty is pretzels with 100 calories
Favorite sweet is cookies with 180 calories
Favorite veggie is carrots with 20 calories
Newcomers to Python may be surprised to learn that unpacking can even be used to swap values in place without the need to create temporary variables. Here, I use typical syntax with indexes to swap the values between two positions in a list as part of an ascending order sorting algorithm:
刚接触Python的人可能会惊讶地发现,解包甚至可以用于交换值,而不需要创建临时变量。这里,作为升序排序算法的一部分,我使用典型的索引语法来交换列表中两个位置的值:
def bubble_sort (a):
for _ in range (len (a)):
for i in range (1, len (a)):
if a [i] < a [i-1]:
temp = a [i]
a [i] = a [i-1]
a [i-1] = temp
names = [ 'pretzels ', 'carrots ', 'arugula ', 'bacon ']
bubble_sort (names)
print (names)
>>>
[ 'arugula ', 'bacon ', 'carrots ', 'pretzels ']
However, with unpacking syntax, it’s possible to swap indexes in a single line:
然而,使用解包语法,可以在一行中交换索引:
def bubble_sort (a):
for _ in range (len (a)):
for i in range (1, len (a)):
if a [i] < a [i-1]:
a [i-1], a [i] = a [i], a [i-1] # Swap
names = [ 'pretzels ', 'carrots ', 'arugula ', 'bacon ']
bubble_sort (names)
print (names)
>>>
[ 'arugula ', 'bacon ', 'carrots ', 'pretzels ']
The way this swap works is that the right side of the assignment (a [i], a[i-1]) is evaluated first, and its values are put into a new temporary, unnamed tuple (such as ( 'carrots ', 'pretzels ') on the first iteration of the loops). Then, the unpacking pattern from the left side of the assignment (a [i-1], a[i]) is used to receive that tuple value and assign it to the variable names a [i-1] and a[i], respectively. This replaces 'pretzels ' with 'carrots ' at index 0 and 'carrots ' with 'pretzels' at index 1. Finally, the temporary unnamed tuple silently goes away.
这种交换的工作方式是首先计算赋值的右侧(a [i], a[i-1]),并将其值放入一个新的临时的、未命名的元组(例如('carrot ', 'pretzels ')在循环的第一次迭代中)。然后,使用赋值左边的解包模式(a [i-1], a[i])来接收该元组值,并将其分别赋给变量名a[i -1]和a[i]。在索引0中将“pretzels”替换为“carrots”,在索引1中将“carrots”替换为“pretzels”。最后,临时的未命名元组悄然消失。
Another valuable application of unpacking is in the target list of for loops and similar constructs, such as comprehensions and generator expressions (see Item 27: “Use Comprehensions Instead of map and filter” for those). As an example for contrast, here I iterate over a list of snacks without using unpacking:
解包的另一个有价值的应用是在for循环和类似结构的目标列表中,比如推导式和生成器表达式(参见第27项:“使用推导式代替map和filter”)。作为对比的例子,我在这里不使用解包的方式迭代一个零食列表:
snacks = [ ( 'bacon ', 350), ( 'donut ', 240), ( 'muffin ', 190)]
for i in range (len (snacks)):
item = snacks [i]
name = item[0]
calories = item[1]
print (f '#{i+1}: {name} has {calories} calories ')
>>>
#1: bacon has 350 calories
#2: donut has 240 calories
#3: muffin has 190 calories
This works, but it’s noisy. There are a lot of extra characters required in order to index into the various levels of the snacks structure. Here, I achieve the same output by using unpacking along with the enumerate built-in function (see Item 7: “Prefer enumerate Over range”) :
这招管用,但有点嘈杂。为了索引零食结构的不同层次,需要添加许多额外的字符。这里,我通过使用解包和enumerate内置函数来实现相同的输出(参见第7项:“使用enumerate而不是range”):
for rank, (name, calories) in enumerate (snacks, 1):
print (f '#{rank}: {name} has {calories} calories ')
>>>
#1: bacon has 350 calories
#2: donut has 240 calories
#3: muffin has 190 calories
This is the Pythonic way to write this type of loop; it’s short and easy to understand. There’s usually no need to access anything using indexes.
这是python编写这种类型循环的方法; 它很短并且很容易理解,通常不需要使用索引访问任何东西。
Python provides additional unpacking functionality for list construction (see Item 13: “Prefer Catch-All Unpacking Over Slicing”), function arguments (see Item 22: “Reduce Visual Noise with Variable Positional Arguments”), keyword arguments (see Item 23: “Provide Optional Behavior with Keyword Arguments”), multiple return values (see Item 19: “Never Unpack More Than Three Variables When Functions Return Multiple Values”), and more.
Python为列表提供了额外的解包功能(参见第13项:" 使用全集解包而不是切片")、函数参数(参见第22项:"使用可变位置参数减少视觉噪声")、关键字参数(参见第23项:"使用关键字参数提供可选行为")、多个返回值(参见第19项:“当函数返回多个值时,不要解包超过三个变量”)等等。
Using unpacking wisely will enable you to avoid indexing when possible, resulting in clearer and more Pythonic code.
明智地使用解包将使您能够在可能的情况下避免索引,从而生成更清晰、更符合python风格的代码。
Things to Remember
要记住的事
✦ Python has special syntax called unpacking for assigning multiple values in a single statement.
✦ Unpacking is generalized in Python and can be applied to any iterable, including many levels of iterables within iterables.
✦ Reduce visual noise and increase code clarity by using unpacking to avoid explicitly indexing into sequences.
✦ Python有特殊的解包语法,用于在单行语句中分配多个值。
✦ 解包在Python中很通用,可以应用于任何可迭代对象,包括可迭代对象中的嵌套的多级别可迭代对象。
✦ 通过使用解包而不是显示地使用序列索引,以减少视觉噪音,增加代码清晰度。