映射和集合类型

?Mapping and Set Types
映射和集合类型
Chapter Topics
Mapping Type: Dictionaries
Operators
Built-in Functions
Built-in Methods
Dictionary Keys
Set Types
Operators
Built-in Functions
Built-in Methods
Related Modules
7

*本章主题
* 映射类型: 字典
* 操作符
* 内建函数
* 内建方法
* 字典的键
* 集合类型
* 操作符
* 内建函数
* 内建方法
* 相关模块


第七章
in this chapter, we take a look at Python’s mapping and set types. As in earlier chapters, an introduction is followed by a discussion of the applicable operators and factory and built-in functions (BIFs) and methods. We then go into more specific usage of each data type.
本章中,我们来讨论Python语言中的映射类型和集合类型。和前面的章节一样,我们首先做一个介绍,然后在来讨论可用操作符,工厂函数、内建函数(BIF)和方法。然后我们再来看看每种数据类型的详细用法。
7.1 Mapping Type: Dictionaries
映射类型:字典
Dictionaries are the sole mapping type in Python. Mapping objects have a one-to-many correspondence between hashable values (keys) and the objects they represent (values). They are similar to Perl hashes and can be generally considered as mutable hash tables. A dictionary object itself is mutable and is yet another container type that can store any number of Python objects, including other container types. What makes dictionaries different from sequence type containers like lists and tuples is the way the data are stored and accessed. Sequence types use numeric keys only (numbered sequentially as indexed offsets from the beginning of the sequence). Mapping types may use most other object types as keys; strings are the most common. Unlike sequence type keys, mapping keys are often, if not directly, associated with the data value that is stored. But because we are no longer using “sequentially ordered” keys with mapping types, we are left with an unordered collection of data.
字典是Python语言中唯一的映射类型。映射类型对象里哈希值(键) 和指向的对象(值)是一对多的关系。 它们与Perl中的哈希类型(译者注:又称关联数组)相似,通常被认为是可变的哈希表。一个字典对象是可变的,它是一个容器类型,能存储任意个数的Python对象,其中也包括其他容器类型。字典类型和序列类型容器类(列表、元组)的区别是存储和访问数据的方式不同。序列类型只用数字类型的键(从序列的开始起按数值顺序索引)。映射类型可以用其他对象类型做键;一般最常见的是用字符串做键(keys)。和序列类型的键不同,映射类型的键(keys)直接,或间接地和存储的数据值相关联。但因为在映射类型中,我们不再用"序列化排序"的键(keys),所以映射类型中的数据是无序排列的。
As it turns out, this does not hinder our use because mappi

ng types do not require a numeric value to index into a container to obtain the desired item. With a key, you are “mapped” directly to your value, hence the term “mapping type.” The reason why they are commonly referred to as hash tables is because that is the exact type of object that dictionaries are. Dictionaries are one of Python’s most powerful data types.
显然,这并不影响我们使用映射类型,因为映射类型不要求用数字值做索引以从一个容器中获取对应的数据项。你可以用键(key)直接 "映射" 到值, 这就是为什么叫映射类型(“mapping type”)的原因。映射类型通常被称做哈希表的原因是字典对象就是哈希类型的。字典是Python中最强大的数据类型之一。

CORE NOTE: What are hash tables and how do they relate to dictionaries?
核心笔记:什么是哈希表?它们与字典的关系是什么?
Sequence types use sequentially ordered numeric keys as index offsets to store your data in an array format. The index number usually has nothing to do with the data value that is being stored. There should also be a way to store data based on another associated value such as a string. We do this all the time in everyday living. You file people’s phone numbers in your address book based on last name, you add events to your calendar or appointment book based on date and time, etc. For each of these examples, an associated value to a data item was your key.
序列类型用有序的数字键做索引将数据以数组的形式存储。一般,索引值与所存储的数据毫无关系。还可以用另一种方式来存储数据:基于某种相关值,比如说一个字符串。我们在日常生活中一直这么做。你把人们的电话号码按照他们的姓记录在电话簿上,你按照时间在日历或约会簿上添加事件,等等。在这些例子中,你的键(key)就是和数据项相关的值。
Hash tables are a data structure that does exactly what we described. They store each piece of data, called a value, based on an associated data item, called a key. Together, these are known as key-value pairs. The hash table algorithm takes your key, performs an operation on it, called a hash function, and based on the result of the calculation, chooses where in the data structure to store your value. Where any one particular value is stored depends on what its key is. Because of this randomness, there is no ordering of the values in the hash table. You have an unordered collection of data.
哈希表是一种数据结构:它按照我们所要求的去工作。哈希表中存储的每一条数据,叫做一个值(value),是根据与它相关的一个被称作为键(key)的数据项进行存储的。键和值合在一起被称为“键-值 对”(key-value pairs)。 哈希表的算法是获取键,对键执行一个叫做哈希函数的操作,并根据计算的结果,选择在数据结构的某个地址中来存储你的

值。任何一个值存储的地址皆取决于它的键。正因为这种随意性,哈希表中的值是没有顺序的。你拥有的是一个无序的数据集。
The only kind of ordering you can obtain is by taking either a dictionary’s set of keys or values.The keys() or values() method returns lists, which are sortable. You can also call items() to get a list of keys and values as tuple pairs and sort that. Dictionaries themselves have no implicit ordering because they are hashes.
你所能获得的有序集合只能是字典中的键的集合或者值的集合。方法Keys() 或 values() 返回一个列表,该列表是可排序的。 你还可以用 items()方法得到包含键、值对的元组的列表来排序。由于字典本身是哈希的,所以是无序的。
Hash tables generally provide good performance because lookups occur fairly quickly once you have a key.
哈希表一般有很好的性能, 因为用键查询相当快。
 Python dictionaries are implemented as resizeable hash tables. If you are familiar with Perl, then we can say that dictionaries are similar to Perl’s associative arrays or hashes.
Python的字典是作为可变的哈希表实现的。如果你熟悉Perl的话, 就可以发现字典与Perl中的"关系数组"或散列相似。

 We will now take a closer look at Python dictionaries. The syntax of a dictionary entry is key:value. Also, dictionary entries are enclosed in braces ( { } ).
现在我们就来研究Python字典。一个字典条目的语法格式是 键:值。 而且,多条字典条目被包含在( { } ) 里。
How to Create and Assign Dictionaries
如何创建字典和给字典赋值
Creating dictionaries simply involves assigning a dictionary to a variable, regardless of whether the dictionary has elements or not:
创建字典只需要把字典赋值给一个变量,不管这个字典是否包含元素:
>>> dict1 = {}
>>> dict2 = {'name': 'earth', 'port': 80}
>>> dict1, dict2
({}, {'port': 80, 'name': 'earth'})
In Python versions 2.2 and newer, dictionaries may also be created using the factory function dict(). We discuss more examples later when we take a closer look at dict(), but here’s a sneak peek for now:
从Python 2.2版本起, 可以用工厂方法 dict() 来创建字典。 当我们详细讨论dict()的时候会看到更多的例子,现在来看一个小例子:
>>> fdict = dict((['x', 1], ['y', 2]))
>>> fdict
{'y': 2, 'x': 1}
In Python versions 2.3 and newer, dictionaries may also be created using a very convenient built-in method for creating a “default” dictionary whose elements all have the same value (defaulting to None if not given), fromkeys():
从Python 2.3版本起, 可以用一个很方便的内建方法fromkeys() 来创建一个"默认"字典, 字典中元素具有相同的值 (如果没有给出, 默认为None):
>>> ddict = {}.fromkeys(('x', 'y'), -1)
>>> ddict
{'y': -1, 'x': -1}
>>>
>

>> edict = {}.fromkeys(('foo', 'bar'))
>>> edict
{'foo': None, 'bar': None}
How to Access Values in Dictionaries
如何访问字典中的值
To traverse a dictionary (normally by key), you only need to cycle through its keys, like this:
要想遍历一个字典(一般用键), 你只需要循环查看它的键, 像这样:
>>> dict2 = {'name': 'earth', 'port': 80}
>>>
>>>> for key in dict2.keys():
... print 'key=%s, value=%s' % (key, dict2[key])
...
key=name, value=earth key=port, value=80
Beginning with Python 2.2, you no longer need to use the keys() method to extract a list of keys to loop over. Iterators were created to simplify accessing of sequence-like objects such as dictionaries and files. Using just the dictionary name itself will cause an iterator over that dictionary to be used in a for loop:
从Python 2.2 开始, 你可以不必再用keys()方法获取供循环使用的键值列表了。 可以
用迭代器来轻松地访问类序列对象(sequence-like objects),比如字典和文件。只需要用字典的名字就可以在 for 循环里遍历字典。
>>> dict2 = {'name': 'earth', 'port': 80}
>>>
>>>> for key in dict2:
... print 'key=%s, value=%s' % (key, dict2[key])
...
key=name, value=earth key=port, value=80
 To access individual dictionary elements, you use the familiar square brackets along with the key to obtain its value:
要得到字典中某个元素的值, 可以用你所熟悉的字典键加上中括号来得到:
>>> dict2['name']
'earth'
>>>
>>> print 'host %s is running on port %d' % \
... (dict2['name'], dict2['port'])
host earth is running on port 80
 Dictionary dict1 defined above is empty while dict2 has two data items. The keys in dict2 are 'name' and 'port', and their associated value items are 'earth' and 80, respectively. Access to the value is through the key, as you can see from the explicit access to the 'name' key.
字典dict1是空的,字典dict2有两个数据元素。字典dict2的键是 'name' 和 'port',它们对应的值分别是'earth' 和 80。就像你看到的,通过键'name'可以得到字典中的元素的值。

 If we attempt to access a data item with a key that is not part of the dictionary, we get an error:
如果我们想访问该字典中的一个数据元素,而它在这个字典中没有对应的键,将会产生一个错误:
>>> dict2['server'] Traceback (innermost last):
 File "", line 1, in ? KeyError: server
 In this example, we tried to access a value with the key 'server' which, as you know from the code above, does not exist. The best way to check if a dictionary has a specific key is to use the dictionary’s has_key() method, or better yet, the in or not in operators starting with version 2.2. The has_key() method will be obsoleted in future versions of Python, so it is best to just use in or not in.
在这个例子中,我们试图获得字典中'server'键所对应的值。你从上面的代

码知道,'server'这个键并不存在。检查一个字典中是否有某个键的最好方法是用字典的 has_key()方法, 或者另一种比较好的方法就是从2.2版本起用的,in 或 not in 操作符。 has_key() 方法将会在未来的Python版本中弃用,所以用in 或 not in是最好的方法。
We will introduce all of a dictionary’s methods below. The Boolean has_key() and the in and not in operators are Boolean, returning True if a dictionary has that key and False otherwise. (In Python versions preceding Boolean constants [older than 2.3], the values returned are 1 and 0, respectively.)
下面我们将介绍字典所有的方法。方法has_key()和 in 以及 not in 操作符都是布尔类型的。对于前两者而言,如果字典中有该键就返回真(True),否则返回假(False)。(Python 2.3版本以前,没有布尔常量,为真时返回1,假时返回0。)
>>> 'server' in dict2 # or dict2.has_key('server') Falser
>>> 'name' in dict # or dict2.has_key('name') True
>>> dict2['name']
'earth'
>>> 'server' in dict2 # 或 dict2.has_key('server')
False
>>> 'name' in dict # 或 dict2.has_key('name')
True
>>> dict2['name']
'earth'
 Here is another dictionary example mixing the use of numbers and strings as keys:
一个字典中混用数字和字符串的例子:
>>> dict3 = {}
>>> dict3[1] = 'abc'
>>> dict3['1'] = 3.14159
>>> dict3[3.2] = 'xyz'
>>> dict3
{3.2: 'xyz', 1: 'abc', '1': 3.14159}
 Rather than adding each key-value pair individually, we could have also entered all the data for dict3 at the same time:
除了逐一地添加每个键-值对外,我们也可以给dict3整体赋值。
dict3 = {3.2: 'xyz', 1: 'abc', '1': 3.14159}
 Creating the dictionary with a set key-value pair can be accomplished if all the data items are known in advance (obviously). The goal of the examples using dict3 is to illustrate the variety of keys that you can use. If we were to pose the question of whether a key for a particular value should be allowed to change, you would probably say, “No.” Right? 如果事先已经知道所有的数据就可以用键-值对来创建一个字典(这是显而易见的)。通过字典dict3的示例说明你可以采用各种类型的数据作为字典的键。如果我们被问到是否可以改变某个字典值的键(key) 时,你可能会说,“不”,对吗?


 Not allowing keys to change during execution makes sense if you think of it this way: Let us say that you created a dictionary element with a key and value. Somehow during execution of your program, the key changed, perhaps due to an altered variable. When you went to retrieve that data value again with the original key, you got a KeyError (since the key changed), and you had no idea how to obtain your value now because the key had somehow been altered. For this reason, keys must be hashable, so numbers and strings are fine, but lists and other dictionaries are not

. (See Section 7.5.2 for why keys must be hashable.)
为什么在执行中字典中的键不允许被改变呢?你这样想就会明白: 比方说, 你创建了一个字典,字典中包含一个元素(一个键和一个值)。可能是由于某个变量的改变导致键发生了改变。这时候你如果用原来的键来取出字典里的数据,会得到KeyError(因为键的值已经改变了),现在你没办法从字典中获取该值了,因为键本身的值发生了变化。由于上面的原因,字典中的键必须是可哈希的, 所以数字和字符串可以作为字典中的键, 但是列表和其他字典不行。(见7.5.2小节 字典的键必须是可哈希的)

How to Update Dictionaries
如何更新字典
You can update a dictionary by adding a new entry or element (i.e., a key-value pair), modifying an existing entry, or deleting an existing entry (see below for more details on removing an entry).
你可以通过以下几种方式对一个字典做修改:添加一个新数据项或新元素(即,一个键-值对);修改一个已存在的数据项;或删除一个已存在的数据项(下面有关于数据项删除操作的详细讲述).
>>> dict2['name'] = 'venus' # update existing entry
>>> dict2['port'] = 6969 # update existing entry
>>> dict2['arch'] = 'sunos5'# add new entry
>>>
>>> print 'host %(name)s is running on port %(port)d' %dict2
host venus is running on port 6969
>>> dict2['name'] = 'venus' # 更新已有条目
>>> dict2['port'] = 6969 # 更新已有条目
>>> dict2['arch'] = 'sunos5'# 增加新条目
>>>
>>> print 'host %(name)s is running on port %(port)d' %dict2
host venus is running on port 6969
 If the key does exist, then its previous value will be overridden by its new value. The print statement above illustrates an alternative way of using the string format operator ( % ), specific to dictionaries. Using the dictionary argument, you can shorten the print request somewhat because naming of the dictionary occurs only once, as opposed to occurring for each element using a tuple argument.
如果字典中该键已经存在,则字典中该键对应的值将被新值替代。上面的print语句展示了另一种在字典中使用字符串格式符( %)的方法。用字典参数可以简化print语句,因为这样做你只须用到一次该字典的名字,而不用在每个元素出现的时候都用元组参数表示。

You may also add the contents of an entire dictionary to another dictionary by using the update() built-in method. We will introduce this method in Section 7.4.
你也可以用内建方法update()将整个字典的内容添加到另一个字典。我们将在7.4节介绍此方法。
How to Remove Dictionary Elements and Dictionaries
如何删除字典元素和字典
Removing an entire dictionary is not a typical operation. Generally, you either remove individual dictionary elements or clear the entire contents o

f a dictionary. However, if you really want to “remove” an entire dictionary, use the del statement (introduced in Section 3.5.5). Here are some deletion examples for dictionaries and dictionary elements:
删除整个字典的操作不常见。通常,你删除字典中的单个元素或是清除整个字典的内容。但是,如果你真想"删除"一个字典,用del 语句 (介绍见小节 3.5.5)。 以下是删除字典和字典元素的例子。
del dict2['name'] # remove entry with key 'name'
dict2.clear() # remove all entries in dict2
del dict2 # delete entire dictionary
dict2.pop('name') # remove & return entry w/key
del dict2['name'] # 删除键为“name”的条目
dict2.clear() # 删除dict2中所有的条目
del dict2 # 删除整个dict2字典
dict2.pop('name') # 删除并返回键为“name”的条目
CORE TIP: Avoid using built-in object names as identifiers for variables!
核心笔记:避免使用内建对象名字作为变量的标识符
For those of you who began traveling in the Python universe before version 2.3, you may have once used dict as an identifier for a dictionary. However, because dict() is now a type and factory function, overriding it may cause you headaches and potential bugs.The interpreter will allow such overriding—hey, it thinks you seem smart and
look like you know what you are doing! So be careful. Do NOT use variables named after built-in types like: dict, list, file, bool, str, input, or len!
如果在Python 2.3 前,你已经开始使用Python,你可能用dict 作为一个字典的标识符。但是,因为 dict() 现在已成为 Python 的类型和工厂方法,重载dict()会给你带来麻烦和潜在的bugs。编译器允许你做这样的重载,它认为你是聪明的,知道自己正在做什么!小心。请不要用 dict, list, file, bool, str, input, len 这样的内建类型为变量命名。
7.2 Mapping Type Operators
映射类型操作符
Dictionaries will work with all of the standard type operators but do not support operations such as concatenation and repetition. Those operations, although they make sense for sequence types, do not translate to mapping types. In the next two subsections, we introduce you to the operators you can use with dictionaries.
字典可以和所有的标准类型操作符一起工作,但却不支持像拼接(concatenation)和重复(repetition)这样的操作。这些操作对序列有意义,可对映射类型行不通。在接下来的两小节里,我们将向你讲述字典中的操作符。
7.2.1 Standard Type Operators
标准类型操作符
The standard type operators were introduced in Chapter 4. Here are some basic examples using some of those operators:
标准类型操作符已在第四章介绍。 下面是一些使用操作符的简单示例:
>>> dict4 = {'abc': 123}
>>> dict5 = {'abc': 456}
>>> dict6 = {'abc': 123, 98.6: 37}
>>> dict7 = {'xyz': 123}
>>> dict4 < dict5
True
>>> (dict4 < dict6) and

(dict4 < dict7) True
>>> (dict5 < dict6) and (dict5 < dict7) True
>>> dict6 < dict7
False
 How are all these comparisons performed? Like lists and tuples, the process is a bit more complex than it is for numbers and strings. The algorithm is detailed in Section 7.3.1.
字典是如何比较的呢? 与列表和元组一样,这个过程比数字和字符串的比较更复杂些。详细算法请见第7.3.1小节。
7.2.2 Mapping Type Operators
映射类型操作符
Dictionary Key-Lookup Operator ( [ ] )
字典的键查找操作符([ ])
The only operator specific to dictionaries is the key-lookup operator, which works very similarly to the single element slice operator for sequence types. For sequence types, an index offset is the sole argument or subscript to access a single element of a sequence. For a dictionary, lookups are by key, so that is the argument rather than an index. The key-lookup operator is used for both assigning values to and retrieving values from a dictionary:
键查找操作符是唯一仅用于字典类型的操作符,它和序列类型里单一元素的切片(slice)操作符很相象。对序列类型来说,用索引做唯一参数或下标(subscript)以获取一个序列中某个元素的值。对字典类型来说,是用键(key)查询(字典中的元素),所以键是参数(argument), 而不是一个索引(index)。键查找操作符既可以用于给字典赋值,也可以用于从字典中取值:

set value 'v' in dictionary with key 'k'
通过键'k',给字典中某元素赋值'v'
lookup value in dictionary with key 'k'
通过键'k',查询字典中某元素的值
(Key) Membership (in, not in)
(键)成员关系操作( in ,not in)
Beginning with Python 2.2, programmers can use the in and not in operators to check key membership instead of the has_key() method:
从Python 2.2起,程序员可以不用has_key()方法,而用 in 和 not in 操作符来检查某个键是否存在于字典中:
>>> 'name' in dict2
True
>>> 'phone' in dict2
False
7.3 Mapping Type Built-in and FactoryFunctions
映射类型的内建函数和工厂函数
7.3.1 Standard Type Functions [type(), str(), and cmp()]
标准类型函数[type()、str()和cmp()]
The type() factory function, when applied to a dict, returns, as you might expect, the dict type, “”. The str() factory function will produce a printable string representation of a dictionary. These are fairly straightforward.
如你所料,对一个字典调用type()工厂方法,会返回字典类型, “”. 调用str()工厂方法将返回该字典的字符串表示形式,这些都很容易理解。
 In each of the last three chapters, we showed how the cmp() BIF worked with numbers, strings, lists, and tuples. So how about dictionaries? Comparisons of dictionaries are based on an algorithm that starts with sizes first, then keys, and finally values. However, using cmp() on dictionaries isn’t usually very usefu

l.
在前面的三个章节里,我们已经讲述了用 cmp() 内建函数来操作数字、字符串、列表和元组。那么字典又是如何比较的呢? 字典是通过这样的算法来比较的: 首先是字典的大小,然后是键,最后是值。可是,用 cmp() 做字典的比较一般不是很有用。

The next subsection goes into further detail about the algorithm used to compare dictionaries, but this is advanced reading, and definitely optional since comparing dictionaries is not very useful or very common.
接下来的小节里,将进一步详细说明字典比较的算法,但这部分是高层次的阅读内容,可以跳过,因为字典的比较不是很有用也不常见。
*Dictionary Comparison Algorithm
字典比较算法
 In the following example, we create two dictionaries and compare them, then slowly modify the dictionaries to show how these changes affect their comparisons:
接下来的例子中,我们建立两个字典进行比较,然后慢慢修改,来看看这些修改对它们之间的比较带来的影响:
>>> dict1 = {}
>>> dict2 = {'host': 'earth', 'port': 80}
>>> cmp(dict1, dict2)
-1
>>> dict1['host'] = 'earth'
>>> cmp(dict1, dict2)
-1
 In the first comparison, dict1 is deemed smaller because dict2 has more elements (2 items vs. 0 items). After adding one element to dict1, it is still smaller (2 vs. 1), even if the item added is also in dict2.
在第一个比较中,dict1 比 dict2小,因为dict2有更多元素(2 个 vs. 0 个)。在向dict1添加一个元素后,dict1仍然比dict2小 (2 vs. 1),虽然添加的元素在dict2中也存在。
>>> dict1['port'] = 8080
>>> cmp(dict1, dict2)
1
>>> dict1['port'] = 80
>>> cmp(dict1, dict2)
0
 After we add the second element to dict1, both dictionaries have the same size, so their keys are then compared. At this juncture, both sets of keys match, parison proceeds to checking their values. The values for the 'host' keys are the same, but when we get to the 'port' key, dict2 is deemed larger because its value is greater than that of dict1’s 'port' key (8080 vs. 80). When resetting dict2’s 'port' key to the same value as dict1’s 'port' key, then both dictionaries form equals: They have the same size, their keys match, and so do their values, hence the reason that 0 is returned by cmp().
在向dict1中添加第二个元素后,两个字典的长度相同,所以用键比较大小。这时键相等,则通过它们的值比较大小。键 'host'的值相同,对于键 'port',dict1中值比dict2中的值大(8080 vs. 80)。当把dict2中'port'的值设成和dict1中的值一样,那么两个字典相等:它们有相同的大小、相同的键、相同的值,所以cmp() 返回值是0。
{译者注: 原文有误:dict2 is deemed larger because its value is greater than that of dict1’s 'port' key (8080 vs. 80). 应为: dict1 is deemed larger because its value is greater than that of dict2

’s 'port' key (8080 vs. 80). }
>>> dict1['prot'] = 'tcp'
>>> cmp(dict1, dict2)
1
>>> dict2['prot'] = 'udp'
>>> cmp(dict1, dict2)
-1
 As soon as an element is added to one of the dictionaries, it immediately becomes the “larger one,” as in this case with dict1. Adding another key- value pair to dict2 can tip the scales again, as both dictionaries’ sizes match and comparison progresses to checking keys and values.
当向两个字典中的任何一个添加新元素时,这个字典马上会成为大的那个字典,就像例子中的dict1一样。向dict2添加键-值对后,因为两个字典的长度又相等了,会继续比较它们的键和值。

>>> cdict = {'fruits':1}
>>> ddict = {'fruits':1}
>>> cmp(cdict, ddict)
0
>>> cdict['oranges'] = 0
>>> ddict['apples'] = 0
>>> cmp(cdict, ddict)
14
Our final example reminds as that cmp() may return values other than ?1, 0,
or 1. The algorithm pursues comparisons in the following order.
上面的例子表明cmp()可以返回除-1,0,1外的其他值。算法按照以下的顺序。
(1) Compare Dictionary Sizes
比较字典长度
If the dictionary lengths are different, then for cmp(dict1, dict2), cmp() will return a positive number if dict1 is longer and a negative number if dict2 is longer. In other words, the dictionary with more keys is greater, i.e.,
如果字典的长度不同,那么用 cmp(dict1, dict2) 比较大小时,如果字典 dict1 比 dict2 长,cmp()返回正值,如果 dict2 比 dict1 长,则返回负值。也就是说,字典中的键的个数越多,这个字典就越大,即:
len(dict1) > len(dict2) ==> dict1 > dict2
(2) Compare Dictionary Keys
比较字典的键
If both dictionaries are the same size, then their keys are compared; the order in which the keys are checked is the same order as returned by the keys() method. (It is important to note here that keys that are the same will map to the same locations in the hash table. This keeps key-checking consistent.) At the point where keys from both do not match, they are directly compared and cmp() will return a positive number if the first differing key for dict1 is greater than the first differing key of dict2.
如果两个字典的长度相同,那就按字典的键比较;键比较的顺序和 keys()方法返回键的顺序相同。 (注意: 相同的键会映射到哈希表的同一位置,这保证了对字典键的检查的一致性。) 这时,如果两个字典的键不匹配时,对这两个(不匹配的键)直接进行比较。当dict1中第一个不同的键大于dict2中第一个不同的键,cmp()会返回正值。
(3) Compare Dictionary Values
比较字典的值
If both dictionary lengths are the same and the keys match exactly, the values for each key in both dictionaries are compared. Once the first key with non- matching values is found, those values are compared directly. Then cmp() will return a positive number if, using the same key, the value in dict1 is greater than

the value in dict2.
如果两个字典的长度相同而且它们的键也完全匹配,则用字典中每个相同的键所对应的值进行比较。一旦出现不匹配的值,就对这两个值进行直接比较。若dict1比dict2中相同的键所对应的值大,cmp()会返回正值。
(4) Exact Match
If we have reached this point, i.e., the dictionaries have the same length, the same keys, and the same values for each key, then the dictionaries are an exact match and 0 is returned.
到此为止,即,每个字典有相同的长度、相同的键、每个键也对应相同的值,则字典完全匹配,返回0值。
Figure 7–1 illustrates the dictionary compare algorithm we just outlined.
图 7-1 说明了上述字典比较的算法
START with both dictionaries
Comparing dictionaries
Lengths No
differ?
Keys No
differ?
Values No
differ?
Yes Yes Yes
return(cmp(len(dict1),len(dict2))
return(cmp(dict1KeyN,dict2KeyN))
return(cmp(dict1ValN,dict2ValN))
return(0)
Figure 7–1 How dictionaries are compared
图 7-1 字典是如何进行比较的
7.3.2 Mapping Type Related Functions
映射类型相关的函数
dict()
The dict() factory function is used for creating dictionaries. If no argument is provided, then an empty dictionary is created. The fun happens when a container object is passed in as an argument to dict(). If the argument is an iterable, i.e., a sequence, an iterator, or an object that supports iteration, then each element of the iterable must come in pairs. For each pair, the first element will be a new key in the dictionary with the second item as its value. Taking a cue from the official Python documentation for dict():
dict()
工厂函数被用来创建字典。如果不提供参数,会生成空字典。当容器类型对象做为一个参数传递给方法dict() 时很有意思。如果参数是可以迭代的,即,一个序列,或是一个迭代器,或是一个支持迭代的对象,那每个可迭代的元素必须成对出现。在每个值对中,第一个元素是字典的键、第二个元素是字典中的值。见Python文档里关于dict()的例子:
>>> dict(zip(('x', 'y'), (1, 2)))
{'y': 2, 'x': 1}
>>> dict([['x', 1], ['y', 2]])
{'y': 2, 'x': 1}
>>> dict([('xy'[i-1], i) for i in range(1,3)])
{'y': 2, 'x': 1}
 If it is a(nother) mapping object, i.e., a dictionary, then dict() will just create a new dictionary and copy the contents of the existing one. The new dictionary is actually a shallow copy of the original one and the same results can be accomplished by using a dictionary’s copy() built-in method. Because creating a new dictionary from an existing one using dict() is measurably slower than using copy(), we recommend using the latter.
如果输入参数是(另)一个映射对象,比如,一个字典对象,对其调用dict()会从存在的字典里复制内容来生成新的字典。新生成的字

典是原来字典对象的浅复制版本, 它与用字典的内建方法 copy() 生成的字典对象是一样的。但是从已存在的字典生成新的字典速度比用copy()方法慢,我们推荐使用copy()。
 Starting in Python 2.3, it is possible to call dict() with an existing dictionary or keyword argument dictionary (function operator, covered in Chapter 11):
从Python 2.3 开始,调用dict()方法可以接受字典或关键字参数字典(函数操作符,第11章):
>>> dict(x=1, y=2)
{'y': 2, 'x': 1}
>>> dict8 = dict(x=1, y=2)
>>> dict8
{'y': 2, 'x': 1}
>>> dict9 = dict(**dict8)
>>> dict9
{'y': 2, 'x': 1}
 We remind viewers that the dict9 example is only an exercise in understanding the calling semantics of dict() and not a realistic example. It would be wiser (and better performance-wise) to execute something more along the lines of:
我们提醒读者dict9的例子只作为了解dict()方法的用途,它不是现实中的例子。使用下面这些行的方法更聪明(效率更好):
>>> dict9 = dict8.copy()
>>> dict9
{'y': 2, 'x': 1}
len()
The len() BIF is flexible. It works with sequences, mapping types, and sets
(as we will find out later on in this chapter). For a dictionary, it returns the
total number of items, that is, key-value pairs:
内建函数len()很灵活。它可用在序列、映射类型和集合上(在本章的后面我们会看到)。对字典调用len(),它会返回所有元素(键-值对)的数目:
>>> dict2 = {'name': 'earth', 'port': 80}
>>> dict2
{'port': 80, 'name': 'earth'}
>>> len(dict2)
2
 We mentioned earlier that dictionary items are unordered. We can see that above, when referencing dict2, the items are listed in reverse order from which they were entered into the dictionary.
我们前面提到字典中的元素是没有顺序的。从上面的例子中可以看到,dict2的元素显示的顺序和输入时的顺序正相反。
hash()
The hash() BIF is not really meant to be used for dictionaries per se, but it can be used to determine whether an object is fit to be a dictionary key (or not). Given an object as its argument, hash() returns the hash value of that object. The object can only be a dictionary key if it is hashable (meaning this function returns a[n integer] value without errors or raising an exception).
内建函数hash()本身并不是为字典设计的方法,但它可以判断某个对象是否可以做一个字典的键。将一个对象作为参数传递给 hash(), 会返回这个对象的哈希值。 只有这个对象是可哈希的,才可作为字典的键 (函数的返回值是整数,不产生错误或异常)。
Numeric values that are equal (when pitted against each other using a comparison operator) hash to the same value (even if their types differ).
如果用比较操作符来比较两个数值,发现它们是相等的,那么即使二者的数据类型不同, 它们也会得到相同的哈希

值。

A TypeError will occur if an unhashable type is given as the argument to hash() (and consequently if an attempt is made to use such an object as the key when assigning a value to a dictionary):
如果非可哈希类型作为参数传递给hash()方法,会产生TypeError错误(因此,如果使用这样的对象作为键给字典赋值时会出错):
>>> hash([])
Traceback (innermost last): File "", line 1, in ?
TypeError: list objects are unhashable
>>>
>>> dict2[{}] = 'foo'
Traceback (most recent call last): File "", line 1, in ?
TypeError: dict objects are unhashable
In Table 7.1, we summarize these three mapping type related functions.
在表7.1中,我们列出以下三个映射类型的相关函数。
Table 7.1 Mapping Type Related Functions
表7.1 映射类型的相关函数
Function Operation
函数 操作
dict([container]) Factory function for creating a dictionary populated with items from container, if provided; if not, an empty dict is created
dict([container]) 创建字典的工厂函数。如果提供了容器类(container),就用其中的条目填充字典,否则就创建一个空字典。
len(mapping) Returns the length of mapping (number of key-value pairs)
len(mapping) 返回映射的长度(键-值对的个数)
hash(obj) Returns hash value of obj
hash(obj) 返回obj的哈希值
7.4 Mapping Type Built-in Methods
映射类型内建方法
Dictionaries have an abundance of methods to help you get the job done, as indicated in Table 7.2.
字典提供了大量方法来帮你做事情,见表 7.2.
 Below, we showcase some of the more common dictionary methods. We have already seen has_key() and its replacements in and not in at work above. Attempting to access a nonexistent key will result in an exception(KeyError) as we saw in Section 7.1.
下面,我们说明字典的一些很常见的方法。在上面的例子里,我们已经看到 has_key() 和它的替代方法 in 和 not in。如我们在7.1小节看到,试图查找一个字典里没有的键值会产生KeyError异常。
Basic dictionary methods focus on their keys and values. These are keys(), which returns a list of the dictionary’s keys, values(), which returns a list of the dictionary’s values, and items(), which returns a list of (key, value) tuple pairs. These are useful when you wish to iterate through a dictionary’s keys or values, albeit in no particular order.
基本的字典方法关注他们的键和值。它们有:keys()方法,返回一个列表,包含字典中所有的键,values()方法,返回一个列表,包含字典中所有的值,items(), 返回一个包含所有(键, 值)元组的列表。这些方法在不按任何顺序遍历字典的键或值时很有用。
>>> dict2.keys()
['port', 'name']
>>>
>>> dict2.values()
[80, 'earth']
>>>
>>> dict2.items()
[('port', 80), ('name', 'earth')]
>>>
>>> for eachKey in dict2.keys():
... print 'dict2 key', eachKey,

'has value', dict2[eachKey]
...
dict2 key port has value 80
dict2 key name has value earth
The keys() method is fairly useful when used in conjunction with a for loop to retrieve a dictionary’s values as it returns a list of a dictionary’s keys.
keys()方法很有用,它返回一个包含字典中所有键的列表,此方法可以与for 循环一起使用来获取字典中的值。
Table 7.2 Dictionary Type Methods
表 7.2 字典类型方法
Method Name Operation
方法名字 操作
dict.clear() a Removes all elements of dict
dict.clear() 删除字典中所有元素
dict.copy() a Returns a (shallow b) copy of dict
dict.copy() 返回字典(浅复制)的一个副本
dict.fromkeys(seq, val=None) c
Creates and returns a new dictionary with the elements of seq as the keys and val as the initial value (defaults to None if not given) for all keys
创建并返回一个新字典,以seq中的元素做该字典的键,val做该字典中所有键对应的初始值(如果不提供此值,则默认为None)
dict.get(key, default=None)a
For key key, returns value or default if key not in dict (note that default’s default is None)
对字典dict中的键key,返回它对应的值value,如果字典中不存在此键,则返回default的值(注意,参数default的默认值为None)
dict.has_key(key)
Returns True if key is in dict, False otherwise; partially deprecated by the in and not in operators in 2.2 but still provides a functional interface
dict.has_key(key)
如果键(key)在字典中存在,返回True,否则返回False. 在Python2.2版本引入in和not in 后,此方法几乎已废弃不用了,但仍提供一个可工作的接口。
dict.items() Returns a list of the (key, value) tuple pairs of dict
dict.items() 返回一个包含字典中(键, 值)对元组的列表
dict.keys() Returns a list of the keys of dict
dict.keys() 返回一个包含字典中键的列表
dict.iter() d
iteritems(), iterkeys(), itervalues() are all methods that behave the same as their non-iterator counterparts but return an iterator instead of a list
dict.iter() d
方法iteritems(), iterkeys(), itervalues()与它们对应的非迭代方法一样,不同的是它们返回一个迭代子,而不是一个列表。
dict.pop(key[, default]) c
Similar to get() but removes and returns dict[key] if key present and raises KeyError if key not in dict and default not given
和方法get()相似,如果字典中key键存在,删除并返回dict[key],如果key键不存在,且没有给出default的值,引发KeyError异常。
dict.setdefault(key, default=None)
Similar to set(), but sets dict[key]=default if key is not already in dict
dict.setdefault(key, default=None)
和方法set()相似,如果字典中不存在key键,由dict[key]=default为它赋值。
dict.update(dict2) Add the key-value pairs of dict2 to dict
dict.update(dict2) 将字典dict2的键-值对添加到字典dict
dict.values() Returns a list of the values of

dict
dict.values() 返回一个包含字典中所有值的列表
a. New in Python 1.5.
a. Python 1.5新增
b. More information regarding shallow and deep copies can be found in Section 6.19.
b. 关于深复制和浅复制的详细信息请参见6.19节.
c. New in Python 2.3.
c. Python 2.3新增
d. New in Python 2.2.
d. Python 2.2新增
e. New in Python 2.0.
e. Python 2.0新增
However, because its items (as with any keys of a hash table) are unordered, imposing some type of order is usually desired.
但是,它返回的元素是没有顺序的(和哈希表中的键(keys)一样),我们通常希望它们能按某种方式排序。
 In Python versions prior to 2.4, you would have to call a dictionary’s keys() method to get the list of its keys, then call that list’s sort() method to get a sorted list to iterate over. Now a built-in function named sorted(), made especially for iterators, exists, which returns a sorted iterator:
在Python 2.4 版本以前, 你只能调用字典的keys()方法获得键的列表,然后调用列表的sort()方法得到一个有序可遍历的列表。现在特别为迭代子设计了一个名为 sorted()的内建函数,它返回一个有序的迭代子:

>>> for eachKey in sorted(dict2):
... print 'dict2 key', eachKey, 'has value', dict2[eachKey]
The update() method can be used to add the contents of one directory{原文错误,应为dictionary} to another. Any existing entries with duplicate keys will be overridden by the new incoming entries. Nonexistent ones will be added. All entries in a dictionary can be removed with the clear() method.
update()方法可以用来将一个字典的内容添加到另外一个字典中。字典中原有的键如果与新添加的键重复,那么重复键所对应的原有条目的值将被新键所对应的值所覆盖。原来不存在的条目则被添加到字典中。clear()方法可以用来删除字典中的所有的条目。
>>> dict2= {'host':'earth', 'port':80}
>>> dict3= {'host':'venus', 'server':'http'}
>>> dict2.update(dict3)
>>> dict2
{'server': 'http', 'port': 80, 'host': 'venus'}
>>> dict3.clear()
>>> dict3
{}
 The copy() method simply returns a copy of a dictionary. Note that this is a shallow copy only. Again, see Section 6.19 regarding shallow and deep copies. Finally, the get() method is similar to using the key-lookup operator ( [ ] ), but allows you to provide a default value returned if a key does not exist. If a key does not exist and a default value is not given, then None is returned. This is a more flexible option than just using key-lookup because you do not have to worry about an exception being raised if a key does not exist.
copy() 方法返回一个字典的副本。注意这只是浅复制。关于浅复制和深复制请阅读小节 6.19。最后要说明,get()方法和键查找(key-lookup)操作符( [ ] )相似,不同的是它允许你为不存在的键提供默认值。如果

该键不存在,也未给出它的默认值,则返回None。此方法比采用键查找(key-lookup)更灵活,因为你不必担心因键不存在而引发异常。

>>> dict4 = dict2.copy()
>>> dict4
{'server': 'http', 'port': 80, 'host': 'venus'}
>>> dict4.get('host')
'venus'
>>> dict4.get('xxx')
>>> type(dict4.get('xxx'))

>>> dict4.get('xxx', 'no such key')
'no such key'
 The built-in method, setdefault(), added in version 2.0, has the sole purpose of making code shorter by collapsing a common idiom: you want to check if a dictionary has a key. If it does, you want its value. If the dictionary does not have the key you are seeking, you want to set a default value and then return it. That is precisely what setdefault() does:
setdefault()是自 2.0 才有的内建方法, 使得代码更加简洁,它实现了常用的语法: 检查字典中是否含有某键。 如果字典中这个键存在,你可以取到它的值。 如果所找的键在字典中不存在,你可以给这个键赋默认值并返回此值。这正是执行setdefault()方法的目的:

>>> myDict = {'host': 'earth', 'port': 80}
>>> myDict.keys()
['host', 'port']
>>> myDict.items()
[('host', 'earth'), ('port', 80)]
>>> myDict.setdefault('port', 8080)
80
>>> myDict.setdefault('prot', 'tcp')
'tcp'
>>> myDict.items()
[('prot', 'tcp'), ('host', 'earth'), ('port', 80)]
 Earlier, we took a brief look at the fromkeys() method, but here are a few more examples:
前面,我们曾简要介绍过fromkeys()方法,下面是更多的示例:
>>> {}.fromkeys('xyz')
{'y': None, 'x': None, 'z': None}
>>>
>>> {}.fromkeys(('love', 'honor'), True)
{'love': True, 'honor': True}
 Currently, the keys(), items(), and values() methods return lists. This can be unwieldy if such data collections are large, and the main reason why iteritems(), iterkeys(), and itervalues() were added to Python in 2.2. They function just like their list counterparts only they return iterators, which by lazier evaluation, are more memory-friendly. In future versions of Python, even more flexible and powerful objects will be returned, tentatively called views. Views are collection interfaces which give you access to container objects. For example, you may be able to delete a key from a view, which would then alter the corresponding dictionary accordingly.
目前,keys(), items(), 和 values()方法的返回值都是列表。数据集如果很大会导致很难处理,这也正是iteritems(), iterkeys(), 和itervalues() 方法被添加到 Python 2.2 的主要原因。这些函数与返回列表的对应方法相似,只是它们返回惰性赋值的迭代器,所以节省内存。未来的Python版本中,甚至会更灵活,那时这些方法将会返回强大的对象,暂叫做视图(views)。视图(views)是访问容器对象的接口集。举例来说,你可以从一个视图(views)中删除某个字典的键,从而改变某个字典


7.5 Dictionary Keys
字典的键
Dictionary values have no restrictions. They can be any arbitrary Python object, i.e., from standard objects to user-defined objects. However, the same cannot be said of keys.
字典中的值没有任何限制。 他们可以是任意Python对象,即,从标准对象到用户自定义对象皆可。但是字典中的键是有类型限制的。
7.5.1 More Than One Entry per Key Not Allowed
7.5.1 不允许一个键对应多个值
One rule is that you are constrained to having only one entry per key. In other words, multiple values per the same key are not allowed. (Container objects such as lists, tuples, and other dictionaries are fine.) When key collisions are detected (meaning duplicate keys encountered during assignment), the last (most recent) assignment wins.
你必须明确一条原则:每个键只能对应一个项。也就是说,一键对应多个值是不允许的。(像列表、元组和其他字典这样的容器对象是可以的。) 当有键发生冲突(即,字典键重复赋值),取最后(最近)的赋值。
>>> dict1 = {' foo':789, 'foo': 'xyz'}
>>> dict1
{'foo': 'xyz'}
>>>
>>> dict1['foo'] = 123
>>> dict1
{'foo': 123}
 Rather than producing an error, Python does not check for key collisions because that would involve taking up memory for each key-value pair assigned. In the above example where the key 'foo' is given twice on the same line, Python applies the key-value pairs from left to right. The value 789 may have been set at first, but is quickly replaced by the string 'xyz'. When assigning a value to a nonexistent key, the key is created for the dictionary and value added, but if the key does exist (a collision), then its current value is replaced. In the above example, the value for the key 'foo' is replaced twice; in the final assignment, 'xyz' is replaced by 123.
Python并不会因字典中的键存在冲突而产生一个错误,它不会检查键的冲突是因为,如果真这样做的话,在每个键-值对赋值的时候都会做检查,这将会占用一定量的内存。在上面的例子里,键'foo'被列出两次,Python从左到右检查键-值对。首先值789被赋值(给键'foo'所对应的值),然后又很快被字符串'xyz'替代。当给字典中一个不存在的键赋值时,键和值会被创建和添加,但如果该键已经存在(键冲突),那此键所对应的值将被替换。上面例子中,键 'foo' 所对应的值被替换了两次;最后的赋值语句,值123代替了值'xyz'。
7.5.2 Keys Must Be Hashable
键必须是可哈希的
As we mentioned earlier in Section 7.1, most Python objects can serve as keys; however they have to be hashable objects—mutable types such as lists and dictionaries are disallowed because they cannot be hashed.
我们在小节7.1说过,大多数Python对象可以作为键;但它们必须是可哈希的对象。像列表和字典这样

的可变类型,由于它们不是可哈希的,所以不能作为键。
All immutable types are hashable, so they can definitely be used as keys. One caveat is numbers: Numbers of the same value represent the same key. In other words, the integer 1 and the float 1.0 hash to the same value, mean- ing that they are identical as keys. 所有不可变的类型都是可哈希的,因此它们都可以做为字典的键。一个要说明的是问题是数字:值相等的数字表示相同的键。换句话来说,整型数字 1 和 浮点数 1.0 的哈希值是相同的,即它们是相同的键。

 Also, there are some mutable objects that are (barely) hashable, so they are eligible as keys, but there are very few of them. One example would be a class that has implemented the __hash__() special method. In the end, an immutable value is used anyway as __hash__() must return an integer.
同时,也有一些可变对象(很少)是可哈希的,它们可以做字典的键,但很少见。举一个例子,一个实现了__hash__() 特殊方法的类。因为__hash__()方法返回一个整数,所以仍然是用不可变的值(做字典的键)。

Why must keys be hashable? The hash function used by the interpreter to calculate where to store your data is based on the value of your key. If the key was a mutable object, its value could be changed. If a key changes, the hash function will map to a different place to store the data. If that was the case, then the hash function could never reliably store or retrieve the associated value. Hashable keys were chosen for the very fact that their values cannot change. (This question can also be found in the Python FAQ.)
为什么键必须是可哈希的?解释器调用哈希函数,根据字典中键的值来计算存储你的数据的位置。如果键是可变对象,它的值可改变。如果键发生变化,哈希函数会映射到不同的地址来存储数据。如果这样的情况发生,哈希函数就不可能可靠地存储或获取相关的数据。选择可哈希的键的原因就是因为它们的值不能改变。(此问题在Python FAQ中也能找到答案)
 We know that numbers and strings are allowed as keys, but what about tuples? We know they are immutable, but in Section 6.17.2, we hinted that they might not be as immutable as they could be. The clearest example of that was when we modified a list object that was one of our tuple elements. To allow tuples as valid keys, one more restriction must be enacted: Tuples are valid keys only if they only contain immutable arguments like numbers and strings.
我们知道数字和字符串可以被用做字典的键,但元组又怎么样呢?我们知道元组是不可变的,但在小节6.17.2, 我们提示过它们也可能不是一成不变的。用元组做有效的键,必须要加限制:元组中只包括像数字和字符串这样的不可变参数,才可以作为字典中有效的键。


We conclude this chapter on dictionaries by presenting a program(userpw.py as in Example 7.1) that manages usernames and passwords in a mock login entry database system. This script accepts new users given that
我们用一个程序(userpw.py 例 7.1), 来为本章关于字典的讲述做个小结。这个程序是用于管理用户名和密码的模拟登录数据系统。脚本接受新用户的信息:
Example 7.1 Dictionary Example (userpw.py)
示例 7.1 字典示例(userpw.py)
This application manages a set of users who join the system with a login name and a password. Once established, existing users can return as long as they remember their login and password. New users cannot create an entry with someone else’s login name.
这个程序管理用于登录系统的用户信息:登录名字和密码。登录用户帐号建立后,已存在用户可以用登录名字和密码重返系统。新用户不能用别人的登录名建立用户帐号。
1 #!/usr/bin/env python
2
3 db = {}
4
5 def newuser():
6 prompt = 'login desired: '
7 while True:
8 name = raw_input(prompt)
9 if db.has_key(name):
10 prompt = 'name taken, try another: '
11 continue
12 else:
13 break
14 pwd = raw_input('passwd: ')
15 db[name] = pwd
16
17 def olduser():
18 name = raw_input('login: ')
19 pwd = raw_input('passwd: ')
20 passwd = db.get(name)
21 if passwd == pwd:
22 print 'welcome back', name
23 else:
24 print 'login incorrect'
25
26 def showmenu():
27 prompt = """
28 (N)ew User Login
29 (E)xisting User Login
30 (Q)uit
Example 7.1 Dictionary Example (userpw.py) (continued)
31
32 Enter choice: """
33
34 done = False
35 while not done:
36
37 chosen = False
38 while not chosen:
39 try:
40 choice = raw_input(prompt).strip()[0].lower()
41 except (EOFError, KeyboardInterrupt):
42 choice = 'q'
43 print '\nYou picked: [%s]' % choice
44 if choice not in 'neq':
45 print 'invalid option, try again'
46 else:
47 chosen = True
49 done = True
50 newuser()
51 olduser()
52
53 if __name__ == '__main__':
54 showmenu()
they provide a login name and a password. Once an “account” has been set up, an existing user can return as long as the user gives the login and correct password. New users cannot create an entry with an existing login name.
他们提供登录名和密码。帐号建立后,已存在用户可用登录名和正确的密码重返系统。新用户不能用别人的登录名建立帐号。
Line-by-Line Explanation
逐行解释
Lines 1–3
After the Unix-startup line, we initialize the program with an empty user database. Because we are not storing the data anywhere, a new user database is created every time this program is executed.
在Unix初始行后,

我们用一个空用户数据库初始化程序。 因为我们没有把数据存储在任何地方,每次程序执行时都会新建一个用户数据库。
Lines 5–15
The newuser() function is the code that serves new users. It checks to see if a name has already been taken, and once a new name is verified, the user is prompted for his or her password (no encryption exists in our simple program), and his or her password is stored in the dictionary with his or her user name as the key.
newuser() 函数用来建立新用户。它检查名字是否已经存在,如果证实是一个新名字,将要求用户输入他或她的密码 (我们这个简单的程序没有加密),用户的密码被存储在字典里,以他们的名字做字典中的键。
Lines 17–24
The olduser() function handles returning users. If a user returns with the correct login and password, a welcome message is issued. Otherwise, the user is notified of an invalid login and returned to the menu. We do not want an infinite loop here to prompt for the correct password because the user may have inadvertently entered the incorrect menu option.
olduser()函数处理返回的用户。如果用户用正确的用户名和密码登录,打出欢迎信息。否则通知用户是无效登录并返回菜单。我们不会采用一个无限循环来提示用户输入正确的密码,因为用户可能会无意进入错误的菜单选项。
Lines 26–51
The real controller of this script is the showmenu() function. The user is presented with a friendly menu. The prompt string is given using triple quotes because it takes place over multiple lines and is easier to manage on multiple lines than on a single line with embedded '\n' symbols. Once the menu is displayed, it waits for valid input from the user and chooses which mode of operation to follow based on the menu choice. The try-except statements we describe here are the same as for the stack.py and queue.py examples from the last chapter (see Section 6.14.1).
真正控制这个脚本的是showmenu()函数,它显示给用户一个友好界面。提示信息被包括在三引号里("""), 这样做是因为提示信息跨多行,而且比单行包含'\n'符号的字符串更容易处理。菜单显示后,它等待用户的有效输入,然后根据菜单选项选择操作方式。try-expect 语句和上章 stack.py queue.py例子里的一样(见 小节 6.14.1).
Lines 53–54
This is the familiar code that will only call showmenu() to start the application if the script was involved directly (not imported). Here is a sample execution of our script:
如果这个脚本被直接执行(不是通过import方式),这行代码会调用showmenu()函数运行程序。这是我们的脚本运行结果:
$ userpw.py
(N)ew User Login
(E)xisting User Login
(Q)uit
Enter choice: n
You picked: [n]
login desired: king arthur passwd: grail
(N)ew User Login
(E)xisting User Login
(

相关文档
最新文档