12.16 字典
从上文可以看出,Python 列表是一种将元素组织在一起的方式。在编程中,你会经常想以另一种方式组织元素,即将某个值和另一个值关联起来。这种组织方式就像电话通讯录将姓名和电话号码关联起来,也像字典将单词和它们的含义关联起来。
Python 字典(dictionary)是一种将两个东西关联在一起的方式。被关联在一起的两个东西分别称为键(key)和值(value)。字典中的每个项(item)或条目(entry)都有一个键和一个值,它们合起来被称为键值对(key-value pair)。一个字典就是一些键值对的集合。
一个简单的例子就是电话通讯录。假设你想保存朋友们的电话号码。你会使用他们的姓名去查找他们的号码(希望你的朋友们没有重名的)。这个姓名就是“键”,即你会用它来查找信息,而电话号码就是“值”,即你要查找的信息。

下面是创建一个 Python 字典的方法,我们用它来存储姓名和电话号码。首先,创建一个空的字典:
>>> phoneNumbers = {}
这个代码看起来和创建列表的方式非常像,只不过它使用的是花括号而不是方括号。
然后,我们来添加一个条目:
>>> phoneNumbers["John"] = "555-1234"
如果我们打印一下字典,它看起来是这样的:
>>> print phoneNumbers
{'John': '555-1234'}
首先显示键,然后是一个冒号,再接着显示值。之所以用引号,是因为在这个例子中键和值刚好都是字符串(不是必需的)。
也可以用另一种方式来完成:
>>> phoneNumbers = {"John": "555-1234"}
我们来添加更多的条目。不像在列表中可以使用 append(),在字典中则没有用于添加新条目的方法。只需要指定新的键和值就行了:
>>> phoneNumbers["Mary"] = "555-6789"
>>> phoneNumbers["Bob"] = "444-4321"
>>> phoneNumbers["Jenny"] = "867-5309"
我们来看一下整个字典:
>>> print phoneNumbers
{'Bob': '444-4321', 'John': '555-1234', 'Mary': '555-6789', 'Jenny': '867-5309'}
我们之所以创建字典,是因为我们可以在字典中查找东西。在这个例子中,我 们希望按姓名来查找电话号码。你可以这样做:
>>> print phoneNumbers["Mary"]
'555-6789'
注意,这里使用方括号来指定你想要找的条目的键。整个字典本身还是被包裹在花括号中。
字典和列表有点类似,但也有一些主要区别。这两种类型都称为“集合”(collection),也就是说,它们都是将其他类型条目集中在一起的组织方式。
它们的一些相似点:
列表和字典都可以包含任意类型(甚至包括列表和字典)的条目,所以你可以有一个包含数字、字符串、对象甚至其他集合的集合。
列表和字典都提供了在集合中查找条目的方法。
它们的一些不同点:
列表是有顺序的(ordered)。如果你按照某种顺序向列表中添加元素,这些元素就会保持这种顺序。你还可以对列表进行排序。字典是无序的(unordered)。如果你向字典中添加内容,然后打印出来,显示的顺序可能会跟添加的顺序不同。
列表中的元素是使用索引访问的,而字典中的条目是使用键来访问的:
>>> print myList[3]
'eggs'
>>> print myDictionary["John"]
'555-1234'
前面提到过,在 Python 中很多东西都是对象,列表和字典也是。所以列表和字典都有一些使用点号表示法来使用的方法。
keys() 方法会列出字典中所有的键:
>>> phoneNumbers.keys()
['Bob', 'John', 'Mary', 'Jenny']
values() 方法会列出字典中所有的值:
>>> phoneNumbers.values()
['444-4321', '555-1234', '555-6789', '867-5309']
其他的语言也有与 Python 字典类似的东西。它们通常被称为关联数组(associative array),因为它们将键和值关联在一起。你可能也会听说它们的另外一个名字——哈希表(hash table)。
和列表一样,字典中的条目也可以是任意类型,包括简单类型(整数、浮点数、字符串)和集合(列表、字典)以及复合类型(对象)。
没错,你可以在字典中包含其他的字典,正如列表中可以包含其他的列表一样。但事实上,这句话并不完全对。只有字典中的值是可以使用字典的,而键的要求更为严格一些。早先我们谈论过可变类型(mutable)与不可变类型(immutable)。字典的键只可以使用不可变类型(布尔、整数、浮点数、字符串和元组)。你不能使用一个列表或者字典来当作键,因为它们是可变类型。
我在上面提到过,字典和列表有一个不同之处,就是字典是无序的。注意,尽管 Bob 的电话是第三个被添加到字典中的,但在打印字典内容时却是第一个显示的。字典没有顺序这个概念,所以对字典进行排序是没有意义的。但有时你希望将字典中的内容按照某种顺序显示出来。虽然字典没有顺序,但可以对列表排序,所以当你拿到键的列表后,就可以对键进行排序,然后按照键的顺序显示字典内容。你可以使用 sorted() 函数来对字典的键排序,像下面这样:
>>> for key in sorted(phoneNumbers.keys()):
print key, phoneNumbers[key]
Bob 444-4321
Jenny 867-5309
John 555-1234
Mary 555-6789
这和你在列表中看到的 sorted() 函数是一样的。如果你细想一下,会发现它是有效的,因为字典的键的集合是一个列表。
那么,如果你想将字典的值(而不是键)按某种顺序输出该怎么办呢?在电话通讯录的例子中,就是按照电话号码从小到大输出。字典的查找过程是单向的,这意味着只能用键去查找值,而不能反过来。所以对值排序会有些困难。但这仍然是可以做到的,只是需要做更多的工作:
>>> for value in sorted(phoneNumbers.values()):
for key in phoneNumbers.keys():
if phoneNumbers[key] == value:
print key, phoneNumbers[key]
Bob 444-4321
John 555-1234
Mary 555-6789
Jenny 867-5309
我们首先取得排序之后的值的列表,然后针对列表中的每个值,循环遍历字典中的所有键,直到找到与该值关联的键。
下面是字典可以做的其他一些事情。
- 使用 del 删除一个条目:
>>> del phoneNumbers["John"]
>>> print phoneNumbers
{'Bob': '444-4321', 'Mary': '555-6789', 'Jenny': '867-5309'
- 使用 clear() 删除所有条目(清空字典):
>>> phoneNumbers.clear()
>>> print phoneNumbers
{}
- 使用 in 确定某个键在字典中是否存在:
>>> phoneNumbers = {'Bob':'444-4321', 'Mary':'555-6789','Jenny':'867-5309'}
>>> "Bob" in phoneNumbers
True
>>> "Barb" in phoneNumbers
False
字典在 Python 代码中使用得很广泛。
这些当然不是有关 Python 字典的全部内容,但你应该对其有了大致的了解,这样你就可以在代码中使用字典,也可以认出在其他代码中出现的字典。
你学到了什么
在这一章,你学到了以下内容。
列表是什么。
如何向列表中增加元素。
如何从列表删除元素。
如何确定列表是否包含某个值。
如何对列表排序。
如何建立列表的副本。
元组。
双重列表。
Python 字典。
测试题
向列表增加元素有哪些方法?
从列表删除元素有哪些方法?
要得到一个列表的有序副本,但又不能改变原来的列表,有哪两种方法?
怎样得出某个值是否在列表中?
如何确定某个值在列表中的位置?
什么是元组?
如何建立双重列表?
如何从一个双重列表中得到一个值?
什么是字典?
如何向字典中增加项?
怎样使用键去查找一个条目?
动手试一试
- 写一个程序,让用户提供 5 个名字。程序要把这 5 个名字保存在一个列表中,最后打印出来。就像这样:
Enter 5 names:
Tony
Paul
Nick
Michel
Kevin
The names are Tony Paul Nick Michel Kevin
修改第 1 题的程序,要求不仅显示原来的名字列表,还要显示出排序后的列表。
修改第 1 题的程序,要求只显示用户键入的第 3 个名字,就像这样:
The third name you entered is: Nick
- 修改第 1 题的程序,让用户替换其中一个名字。用户应该能选择要替换哪个名字,然后键入新名字。最后显示这个新的列表:
Enter 5 names:
Tony
Paul
Nick
Michel
Kevin
The names are Tony Paul Nick Michel Kevin
Replace one name. Which one? (1-5): 4
New name: Peter
The names are Tony Paul Nick Peter Kevin
- 编写一个字典程序,让用户可以添加单词和定义,然后可以查找这些单词。确保当要查找的单词不存在时,用户能够知晓。运行的时候,它应该是像这样的:
Add or look up a word (a/l)? a
Type the word: computer
Type the definition: A machine that does very fast math
Word added!
Add or look up a word (a/l)? l
Type the word: computer
A machine that does very fast math
Add or look up a word (a/l)? l
Type the word: qwerty
That word isn't in the dictionary yet.
