Chapter 12 Tuples 第 12 章 元组
本页译自 Think Python 2e(Allen B. Downey)· Chapter 12 Tuples。代码块保留英文原文不翻译;正文段段对照,中文块可用右下角按钮隐藏。
12.1 Tuples are immutable 12.1 元组不可变
A tuple is a sequence of values. The values can be any type, and they are indexed by integers, so in that respect tuples are a lot like lists. The important difference is that tuples are immutable.
Syntactically, a tuple is a comma-separated list of values:
>>> t = 'a', 'b', 'c', 'd', 'e'
Although it is not necessary, it is common to enclose tuples in parentheses:
>>> t = ('a', 'b', 'c', 'd', 'e')
To create a tuple with a single element, you have to include a final comma:
>>> t1 = 'a',
>>> type(t1)
<type 'tuple'>
A value in parentheses is not a tuple:
>>> t2 = ('a')
>>> type(t2)
<type 'str'>
Another way to create a tuple is the built-in function tuple. With no argument, it creates an empty tuple:
tuple。不带参数时,它会创建一个空元组:tuple0010
If the argument is a sequence (string, list or tuple), the result is a tuple with the elements of the sequence:
tuple0011
Because tuple is the name of a built-in function, you should avoid using it as a variable name.
tuple 是内置函数的名字,你应该避免把它用作变量名。Most list operators also work on tuples. The bracket operator indexes an element:
tuple0014
And the slice operator selects a range of elements.
tuple0015
But if you try to modify one of the elements of the tuple, you get an error:
tuple0016
You can’t modify the elements of a tuple, but you can replace one tuple with another:
tuple0017
12.2 Tuple assignment 12.2 元组赋值
It is often useful to swap the values of two variables. With conventional assignments, you have to use a temporary variable. For example, to swap a and a:
a 和 a:tuple0022
This solution is cumbersome; tuple assignment is more elegant:
tuple0023
The left side is a tuple of variables; the right side is a tuple of expressions. Each value is assigned to its respective variable. All the expressions on the right side are evaluated before any of the assignments.
The number of variables on the left and the number of values on the right have to be the same:
tuple0024
More generally, the right side can be any kind of sequence (string, list or tuple). For example, to split an email address into a user name and a domain, you could write:
tuple0025
The return value from tuple is a list with two elements; the first element is assigned to tuple, the second to tuple0.
tuple 的返回值是一个包含两个元素的列表:第一个元素赋给 tuple,第二个赋给 tuple0。tuple0032
12.3 Tuples as return values 12.3 元组作为返回值
Strictly speaking, a function can only return one value, but if the value is a tuple, the effect is the same as returning multiple values. For example, if you want to divide two integers and compute the quotient and remainder, it is inefficient to compute a00 and then a00. It is better to compute them both at the same time.
a00 再算 a00 效率很低,最好同时算出来。The built-in function tuple0 takes two arguments and returns a tuple of two values, the quotient and remainder. You can store the result as a tuple:
tuple0 接受两个参数,返回一个包含两个值的元组,即商和余数。你可以把结果存成一个元组:tuple0039
Or use tuple assignment to store the elements separately:
tuple0040
Here is an example of a function that returns a tuple:
tuple0041
a00 and a00 are built-in functions that find the largest and smallest elements of a sequence. tuple00 computes both and returns a tuple of two values.
a00 和 a00 是找出序列中最大、最小元素的内置函数。tuple00 同时算出两者,返回一个包含两个值的元组。12.4 Variable-length argument tuples 12.4 可变长实参元组
Functions can take a variable number of arguments. A parameter name that begins with a gathers arguments into a tuple. For example, tuple004 takes any number of arguments and prints them:
a 开头的形参会把实参打包成一个元组。例如,tuple005 接受任意数量的实参并把它们打印出来:tuple0052
The gather parameter can have any name you like, but a000 is conventional. Here’s how the function works:
a000。下面是这个函数的运行效果:tuple0055
The complement of gather is scatter. If you have a sequence of values and you want to pass it to a function as multiple arguments, you can use the a operator. For example, tuple0 takes exactly two arguments; it doesn’t work with a tuple:
a 运算符。例如,tuple0 正好接受两个实参,不能直接给它一个元组:tuple0060
But if you scatter the tuple, it works:
tuple0061
Exercise 1
Many of the built-in functions use variable-length argument tuples. For example, a00 and a00 can take any number of arguments:
a00 和 a00 可以接受任意数量的实参:tuple0066
But a00 does not.
a00 不行。tuple0069
Write a function called tuple0 that takes any number of arguments and returns their sum.
tuple0 的函数,接受任意数量的实参并返回它们的和。12.5 Lists and tuples 12.5 列表与元组
a00 is a built-in function that takes two or more sequences and “zips” them into a list of tuples where each tuple contains one element from each sequence. In Python 3, a00 returns an iterator of tuples, but for most purposes, an iterator behaves like a list.
a00 是一个内置函数,它接受两个或更多序列,把它们「拉链」式拼成元组的列表,每个元组包含各序列中的一个元素。在 Python 3 中,a00 返回的是元组的迭代器,但在大多数情况下,迭代器和列表表现一致。This example zips a string and a list:
tuple0076
The result is a list of tuples where each tuple contains a character from the string and the corresponding element from the list.
If the sequences are not the same length, the result has the length of the shorter one.
tuple0077
You can use tuple assignment in a a00 loop to traverse a list of tuples:
a00 循环里用元组赋值来遍历元组列表:tuple0080
Each time through the loop, Python selects the next tuple in the list and assigns the elements to tuple0 and tuple0. The output of this loop is:
tuple0 和 tuple0。这个循环的输出是:tuple0085
If you combine a00, a00 and tuple assignment, you get a useful idiom for traversing two (or more) sequences at the same time. For example, tuple0088 takes two sequences, a0 and a0, and returns a000 if there is an index a such that tuple0093 :
a00、a00 和元组赋值组合起来,就得到一种同时遍历两个(或更多)序列的常用写法。例如,tuple0096 接受两个序列 a0 和 a0,只要存在某个下标 a 使得 tuple0100 ,就返回 a000:tuple0102
If you need to traverse the elements of a sequence and their indices, you can use the built-in function tuple0103:
tuple0104:tuple0105
The output of this loop is:
tuple0106
Again.
12.6 Dictionaries and tuples 12.6 字典与元组
Dictionaries have a method called tuple that returns a list of tuples, where each tuple is a key-value pair.
tuple 的方法,它返回一个元组列表,每个元组是一个键值对。tuple0109
As you should expect from a dictionary, the items are in no particular order. In Python 3, tuple returns an iterator, but for many purposes, iterators behave like lists.
tuple 返回的是一个迭代器,但在很多情况下,迭代器表现和列表一样。Going in the other direction, you can use a list of tuples to initialize a new dictionary:
tuple0112
Combining a000 with a00 yields a concise way to create a dictionary:
a000 和 a00 组合起来,就得到一种简洁的建字典方式:tuple0117
The dictionary method tuple0 also takes a list of tuples and adds them, as key-value pairs, to an existing dictionary.
tuple0 方法也接受元组列表,把它们作为键值对添加到已有的字典中。Combining tuple, tuple assignment and a00, you get the idiom for traversing the keys and values of a dictionary:
tuple、元组赋值和 a00 组合起来,就得到遍历字典键和值的常用写法:tuple0124
The output of this loop is:
tuple0125
Again.
It is common to use tuples as keys in dictionaries (primarily because you can’t use lists). For example, a telephone directory might map from last-name, first-name pairs to telephone numbers. Assuming that we have defined a000, tuple and tuple0, we could write:
a000、tuple 和 tuple0,可以这样写:tuple0132
The expression in brackets is a tuple. We could use tuple assignment to traverse this dictionary.
tuple0133
This loop traverses the keys in tuple0134, which are tuples. It assigns the elements of each tuple to a000 and tuple, then prints the name and corresponding telephone number.
tuple0137 里的键,那些键都是元组。它把每个元组的元素赋给 a000 和 tuple,然后打印姓名和对应的电话号码。Figure 12.1: State diagram.
But in a larger diagram you might want to leave out the details. For example, a diagram of the telephone directory might appear as in Figure 12.2.
Figure 12.2: State diagram.
Here the tuples are shown using Python syntax as a graphical shorthand.
The telephone number in the diagram is the complaints line for the BBC, so please don’t call it.
12.7 Comparing tuples 12.7 比较元组
The relational operators work with tuples and other sequences; Python starts by comparing the first element from each sequence. If they are equal, it goes on to the next elements, and so on, until it finds elements that differ. Subsequent elements are not considered (even if they are really big).
tuple0140
The a000 function works the same way. It sorts primarily by first element, but in the case of a tie, it sorts by second element, and so on.
a000 函数也是同样的道理。它主要按第一个元素排序,遇到并列时再按第二个元素排序,依此类推。This feature lends itself to a pattern called DSU for
- Decorate
- a sequence by building a list of tuples with one or more sort keys preceding the elements from the sequence,
- Sort
- the list of tuples, and
- Undecorate
- by extracting the sorted elements of the sequence.
- Decorate 装饰
- 先构造一个元组列表来包装序列:在每个元素前面加上一个或多个排序键,
- Sort 排序
- 对这个元组列表排序,
- Undecorate 还原
- 再从中取出排好序的元素。
For example, suppose you have a list of words and you want to sort them from longest to shortest:
tuple0143
The first loop builds a list of tuples, where each tuple is a word preceded by its length.
a000 compares the first element, length, first, and only considers the second element to break ties. The keyword argument tuple0145 tells a000 to go in decreasing order.
a000 先比较第一个元素(即长度),只有当长度并列时才看第二个元素。关键字参数 tuple0148 让 a000 按降序排列。The second loop traverses the list of tuples and builds a list of words in descending order of length.
Exercise 2
In this example, ties are broken by comparing words, so words with the same length appear in reverse alphabetical order. For other applications you might want to break ties at random. Modify this example so that words with the same length appear in random order. Hint: see the tuple0 function in the tuple0 module. Solution: tuple0152 .
tuple0 模块里的 tuple0 函数。答案见 tuple0155 。12.8 Sequences of sequences 12.8 序列的序列
I have focused on lists of tuples, but almost all of the examples in this chapter also work with lists of lists, tuples of tuples, and tuples of lists. To avoid enumerating the possible combinations, it is sometimes easier to talk about sequences of sequences.
In many contexts, the different kinds of sequences (strings, lists and tuples) can be used interchangeably. So how and why do you choose one over the others?
To start with the obvious, strings are more limited than other sequences because the elements have to be characters. They are also immutable. If you need the ability to change the characters in a string (as opposed to creating a new string), you might want to use a list of characters instead.
Lists are more common than tuples, mostly because they are mutable. But there are a few cases where you might prefer tuples:
- In some contexts, like a
tuple0 statement, it is syntactically simpler to create a tuple than a list. In other contexts, you might prefer a list. - If you want to use a sequence as a dictionary key, you have to use an immutable type like a tuple or string.
- If you are passing a sequence as an argument to a function, using tuples reduces the potential for unexpected behavior due to aliasing.
- 有些场合(比如
tuple0 语句)里,构造一个元组比构造列表在语法上更简单。别的场合你或许更想要列表。 - 如果你想把一个序列用作字典的键,就必须用元组或字符串这样的不可变类型。
- 如果把序列作为实参传给函数,用元组能减少因别名问题引发意外行为的机会。
Because tuples are immutable, they don’t provide methods like a000 and tuple01, which modify existing lists. But Python provides the built-in functions tuple0 and tuple016, which take any sequence as a parameter and return a new list with the same elements in a different order.
a000 和 tuple01 这种会修改已有列表的方法。但 Python 提供了内置函数 tuple0 和 tuple016,它们接受任意序列作参数,返回元素顺序不同、内容相同的新列表。12.9 Debugging 12.9 调试
Lists, dictionaries and tuples are known generically as data structures; in this chapter we are starting to see compound data structures, like lists of tuples, and dictionaries that contain tuples as keys and lists as values. Compound data structures are useful, but they are prone to what I call shape errors; that is, errors caused when a data structure has the wrong type, size or composition. For example, if you are expecting a list with one integer and I give you a plain old integer (not in a list), it won’t work.
To help debug these kinds of errors, I have written a module called tuple0166 that provides a function, also called tuple0167 , that takes any kind of data structure as an argument and returns a string that summarizes its shape. You can download it from tuple0168
tuple0169 的模块,它提供一个同名函数,接受任意类型的数据结构作参数,返回一个概括其形状的字符串。你可以从 tuple0170 下载。Here’s the result for a simple list:
tuple0171
A fancier program might write “list of 3 ints,” but it was easier not to deal with plurals. Here’s a list of lists:
tuple0172
If the elements of the list are not the same type, tuple0173 groups them, in order, by type:
tuple0174 会按类型依次分组:tuple0175
Here’s a list of tuples:
tuple0176
And here’s a dictionary with 3 items that map integers to strings.
tuple0177
If you are having trouble keeping track of your data structures, tuple0178 can help.
tuple0179 能帮上忙。12.10 Glossary 12.10 术语表
- tuple:
- An immutable sequence of elements.
- tuple assignment:
- An assignment with a sequence on the right side and a tuple of variables on the left. The right side is evaluated and then its elements are assigned to the variables on the left.
- gather:
- The operation of assembling a variable-length argument tuple.
- scatter:
- The operation of treating a sequence as a list of arguments.
- DSU:
- Abbreviation of “decorate-sort-undecorate,” a pattern that involves building a list of tuples, sorting, and extracting part of the result.
- data structure:
- A collection of related values, often organized in lists, dictionaries, tuples, etc.
- shape (of a data structure):
- A summary of the type, size and composition of a data structure.
- tuple 元组:
- 不可变的元素序列。
- tuple assignment 元组赋值:
- 一种赋值:右边是一个序列,左边是一组变量。先对右边求值,再将其元素赋给左边的变量。
- gather 打包:
- 把可变长实参组装成元组(可变长实参元组)的操作。
- scatter 拆包:
- 把序列当作实参列表来使用的操作。
- DSU 模式:
- 「decorate-sort-undecorate(装饰-排序-还原)」的缩写,指先构造元组列表、排序、再取出部分结果的一种套路。
- data structure 数据结构:
- 一组相关值的集合,常以列表、字典、元组等形式组织。
- shape(数据结构的形状):
- 对数据结构类型、大小与构成的概括描述。
12.11 Exercises 12.11 习题
Exercise 3
Write a function called tuple0180 that takes a string and prints the letters in decreasing order of frequency. Find text samples from several different languages and see how letter frequency varies between languages. Compare your results with the tables at tuple0181 . Solution: tuple0182 .
tuple0183 的函数,接受一个字符串,按字母出现频率从高到低打印。找几种不同语言的文本样本,看看字母频率因语言而异的情况。把你的结果和 tuple0184 的表格对照。答案见 tuple0185 。Exercise 4
More anagrams!
- Write a program that reads a word list from a file (see Section 9.1) and prints all the sets of words that are anagrams.
Here is an example of what the output might look like:
tuple0186 Hint: you might want to build a dictionary that maps from a set of letters to a list of words that can be spelled with those letters. The question is, how can you represent the set of letters in a way that can be used as a key? - Modify the previous program so that it prints the largest set of anagrams first, followed by the second largest set, and so on.
- In Scrabble a “bingo” is when you play all seven tiles in your rack, along with a letter on the board, to form an eight-letter word. What set of 8 letters forms the most possible bingos? Hint: there are seven.
Solution:
tuple0187 .
- 写一个程序,从文件里读入单词列表(见第 9.1 节),打印出所有互为变位词的单词集合。
下面是一种可能的输出样子:
(上方代码块为英文输出示例,不译。)提示:你可以建一个字典,把「一组字母」映射到能用这些字母拼出的单词列表。问题在于,怎样表示这组字母才能用作键?
- 修改上面的程序,让它先打印最大的变位词集合,再打印第二大的,依此类推。
- 在 Scrabble 拼字游戏里,「bingo」指你用手上七块牌加上棋盘上的一个字母,拼出一个八个字母的单词。哪八字母组合能拼出的 bingo 最多?提示:共有七种。
答案见
tuple0188 。
Exercise 5
Two words form a “metathesis pair” if you can transform one into the other by swapping two letters; for example, “converse” and “conserve.” Write a program that finds all of the metathesis pairs in the dictionary. Hint: don’t test all pairs of words, and don’t test all possible swaps. Solution: tuple0189 . Credit: This exercise is inspired by an example at tuple0190 .
tuple0191 。致谢:本题灵感来自 tuple0192 的一个例子。Exercise 6
Here’s another Car Talk Puzzler (tuple0193 ):
tuple0194 ):
What is the longest English word, that remains a valid English word, as you remove its letters one at a time?
哪个最长的英文单词,在每次去掉一个字母之后,依然是一个合法的英文单词?Now, letters can be removed from either end, or the middle, but you can’t rearrange any of the letters. Every time you drop a letter, you wind up with another English word. If you do that, you’re eventually going to wind up with one letter and that too is going to be an English word—one that’s found in the dictionary. I want to know what’s the longest word and how many letters does it have?
字母可以从两端或中间去掉,但你不能重新排列任何字母。每去掉一个字母,就得到另一个英文单词。这样做下去,最终会只剩一个字母,而那个字母本身也得是个字典里能查到的英文单词。我想知道最长的词是哪个,它有几个字母?I’m going to give you a little modest example: Sprite. Ok? You start off with sprite, you take a letter off, one from the interior of the word, take the r away, and we’re left with the word spite, then we take the e off the end, we’re left with spit, we take the s off, we’re left with pit, it, and I.
我给你一个小例子:Sprite。从 sprite 开始,去掉一个内部的字母 r,剩下 spite;再从末尾去掉 e,剩下 spit;去掉 s,剩下 pit、it、I。
Write a program to find all words that can be reduced in this way, and then find the longest one.
This exercise is a little more challenging than most, so here are some suggestions:
- You might want to write a function that takes a word and computes a list of all the words that can be formed by removing one letter. These are the “children” of the word.
- Recursively, a word is reducible if any of its children are reducible. As a base case, you can consider the empty string reducible.
- The wordlist I provided,
tuple0195, doesn’t contain single letter words. So you might want to add “I”, “a”, and the empty string. - To improve the performance of your program, you might want to memoize the words that are known to be reducible.
- 你可以写一个函数,接受一个单词,算出去掉一个字母后能得到的所有单词。这些就是该词的「子词」。
- 递归地看,只要某个词的任一子词可缩减,这个词就可缩减。基础情形可以把空串视为可缩减。
- 我提供的词表
tuple0196 不含单字母单词,所以你可能要补上 I、a 和空串。 - 为了提升程序性能,你可以把已知可缩减的单词做记忆化(memoize)缓存。
Solution: tuple0197 .
tuple0198 。