第13课:常用数据结构之字典

迄今为止,我们已经为大家介绍了Python中的三种容器型数据类型(列表、元组、集合),但是这些数据类型仍然不足以帮助我们解决所有的问题。例如,我们需要一个变量来保存一个人的多项信息,包括:姓名、年龄、身高、体重、家庭住址、本人手机号、紧急联系人手机号,此时你会发现,我们之前学过的列表、元组和集合类型都不够好使。

1person1 = ['王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877']
2person2 = ('王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877')
3person3 = {'王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877'}

集合肯定是最不合适的,因为集合中不能有重复元素,如果一个人的年龄和体重刚好相同,那么集合中就会少一项信息;同理,如果这个人的手机号和紧急联系人手机号是相同的,那么集合中又会少一项信息。另一方面,虽然列表和元组可以把一个人的所有信息都保存下来,但是当你想要获取这个人的手机号或家庭住址时,你得先知道他的手机号是列表或元组中的第几个元素。总之,在遇到上述的场景时,列表、元组、集合都不是最合适的选择,此时我们需要字典(dictionary)类型,这种数据类型最适合把相关联的信息组装到一起,可以帮助我们解决 Python 程序中为真实事物建模的问题。

说到字典这个词,大家一定不陌生,读小学的时候,每个人手头基本上都有一本《新华字典》,如下图所示。

Python 程序中的字典跟现实生活中的字典很像,它以键值对(键和值的组合)的方式把数据组织到一起,我们可以通过键找到与之对应的值并进行操作。就像《新华字典》中,每个字(键)都有与它对应的解释(值)一样,每个字和它的解释合在一起就是字典中的一个条目,而字典中通常包含了很多个这样的条目。

创建和使用字典

Python 中创建字典可以使用{}字面量语法,这一点跟上一节课讲的集合是一样的。但是字典的{} 中的元素是以键值对的形式存在的,每个元素由:分隔的两个值构成,:前面是键,:后面是值,代码如下所示。

1xinhua = {
2    '麓': '山脚下',
3    '路': '道,往来通行的地方;方面,地区:南~货,外~货;种类:他俩是一~人',
4    '蕗': '甘草的别名',
5    '潞': '潞水,水名,即今山西省的浊漳河;潞江,水名,即云南省的怒江'
6}
7print(xinhua)
8person = {
9    'name': '王大锤',
10    'age': 55,
11    'height': 168,
12    'weight': 60,
13    'addr': '成都市武侯区科华北路62号1栋101', 
14    'tel': '13122334455',
15    'emergence contact': '13800998877'
16}
17print(person)

通过上面的代码,相信大家已经看出来了,用字典来保存一个人的信息远远优于使用列表或元组,因为我们可以用: 前面的键来表示条目的含义,而:后面就是这个条目所对应的值。

当然,如果愿意,我们也可以使用内置函数dict或者是字典的生成式语法来创建字典,代码如下所示。

1# dict函数(构造器)中的每一组参数就是字典中的一组键值对
2person = dict(name='王大锤', age=55, height=168, weight=60, addr='成都市武侯区科华北路62号1栋101')
3print(person)  # {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
4
5# 可以通过Python内置函数zip压缩两个序列并创建字典
6items1 = dict(zip('ABCDE', '12345'))
7print(items1)  # {'A': '1', 'B': '2', 'C': '3', 'D': '4', 'E': '5'}
8items2 = dict(zip('ABCDE', range(1, 10)))
9print(items2)  # {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5}
10
11# 用字典生成式语法创建字典
12items3 = {x: x ** 3 for x in range(1, 6)}
13print(items3)  # {1: 1, 2: 8, 3: 27, 4: 64, 5: 125}

想知道字典中一共有多少组键值对,仍然是使用len函数;如果想对字典进行遍历,可以用for循环,但是需要注意,for 循环只是对字典的键进行了遍历,不过没关系,在学习了字典的索引运算后,我们可以通过字典的键获取到和这个键对应的值。

1person = {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
2print(len(person))  # 5
3for key in person:
4    print(key)

字典的运算

对于字典类型来说,成员运算和索引运算肯定是很重要的,前者可以判定指定的键在不在字典中,后者可以通过键获取对应的值或者向字典中添加新的键值对。值得注意的是,字典的索引不同于列表的索引,列表中的元素因为有属于自己有序号,所以列表的索引是一个整数;字典中因为保存的是键值对,所以字典需要用键去索引对应的值。需要 特别提醒大家注意的是,字典中的键必须是不可变类型,例如整数(int)、浮点数(float)、字符串(str)、元组(tuple )等类型,这一点跟集合类型对元素的要求是一样的;很显然,之前我们讲的列表(list)和集合(set )不能作为字典中的键,字典类型本身也不能再作为字典中的键,因为字典也是可变类型,但是字典可以作为字典中的值。大家可以先看看下面的代码,了解一下字典的成员运算和索引运算。

1person = {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
2
3# 成员运算
4print('name' in person)  # True
5print('tel' in person)   # False
6
7# 索引运算
8print(person['name'])
9print(person['addr'])
10person['age'] = 25
11person['height'] = 178
12person['tel'] = '13122334455'
13person['signature'] = '你的男朋友是一个盖世垃圾,他会踏着五彩祥云去迎娶你的闺蜜'
14print(person)
15
16# 循环遍历
17for key in person:
18    print(f'{key}:\t{person[key]}')

需要注意,在通过索引运算获取字典中的值时,如指定的键没有在字典中,将会引发KeyError异常。

字典的方法

字典类型的方法基本上都跟字典的键值对操作相关,其中get方法可以通过键来获取对应的值。跟索引运算不同的是,get 方法在字典中没有指定的键时不会产生异常,而是返回None或指定的默认值,代码如下所示。

1person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
2print(person.get('name'))       # 王大锤
3print(person.get('sex'))        # None
4print(person.get('sex', True))  # True

如果需要获取字典中所有的键,可以使用keys方法;如果需要获取字典中所有的值,可以使用values方法。字典还有一个名为items 的方法,它会将键和值组装成二元组,通过该方法来遍历字典中的元素也是非常方便的。

1person = {'name': '王大锤', 'age': 25, 'height': 178}
2print(person.keys())    # dict_keys(['name', 'age', 'height'])
3print(person.values())  # dict_values(['王大锤', 25, 178])
4print(person.items())   # dict_items([('name', '王大锤'), ('age', 25), ('height', 178)])
5for key, value in person.items():
6    print(f'{key}:\t{value}')

字典的update方法会用一个字典更新另一个字典中的键值对。例如,有两个字典xy,当执行x.update(y)操作时,xy 相同的键对应的值会y中的值被更新,而y中有但x中没有的键值对会直接添加到x中,代码如下所示。

1person1 = {'name': '王大锤', 'age': 55, 'height': 178}
2person2 = {'age': 25, 'addr': '成都市武侯区科华北路62号1栋101'}
3person1.update(person2)
4print(person1)  # {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}

可以通过poppopitem方法从字典中删除元素,前者会返回键对应的值,但是如果字典中不存在指定的键,会引发KeyError 错误;后者在删除元素时,会返回键和值组成的二元组。字典的clear方法会清空字典中所有的键值对,代码如下所示。

1person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
2print(person.pop('age'))  # 25
3print(person)             # {'name': '王大锤', 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
4print(person.popitem())   # ('addr', '成都市武侯区科华北路62号1栋101')
5print(person)             # {'name': '王大锤', 'height': 178}
6person.clear()
7print(person)             # {}

跟列表一样,从字典中删除元素也可以使用del关键字,在删除元素的时候如果指定的键索引不到对应的值,一样会引发KeyError 错误,具体的做法如下所示。

1person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
2del person['age']
3del person['addr']
4print(person)  # {'name': '王大锤', 'height': 178}

字典的应用

我们通过几个简单的例子来看看如何使用字典类型解决一些实际的问题。

例子1:输入一段话,统计每个英文字母出现的次数,按出现次数从高到低输出。

1sentence = input('请输入一段话: ')
2counter = {}
3for ch in sentence:
4    if 'A' <= ch <= 'Z' or 'a' <= ch <= 'z':
5        counter[ch] = counter.get(ch, 0) + 1
6sorted_keys = sorted(counter, key=counter.get, reverse=True)
7for key in sorted_keys:
8    print(f'{key} 出现了 {counter[key]} 次.')

输入:

Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.

输出:

e 出现了 27 次. n 出现了 21 次. a 出现了 18 次. i 出现了 18 次. s 出现了 16 次. t 出现了 16 次. o 出现了 14 次. h 出现了 13 次. r 出现了 10 次. d 出现了 9 次. l 出现了 9 次. g 出现了 6 次. u 出现了 6 次. f 出现了 6 次. c 出现了 6 次. y 出现了 5 次. b 出现了 5 次. m 出现了 4 次. p 出现了 3 次. w 出现了 2 次. v 出现了 2 次. M 出现了 1 次. k 出现了 1 次. x 出现了 1 次.

例子2:在一个字典中保存了股票的代码和价格,找出股价大于100元的股票并创建一个新的字典。

说明:可以用字典的生成式语法来创建这个新字典。

1stocks = {
2    'AAPL': 191.88,
3    'GOOG': 1186.96,
4    'IBM': 149.24,
5    'ORCL': 48.44,
6    'ACN': 166.89,
7    'FB': 208.09,
8    'SYMC': 21.29
9}
10stocks2 = {key: value for key, value in stocks.items() if value > 100}
11print(stocks2)

输出:

{'AAPL': 191.88, 'GOOG': 1186.96, 'IBM': 149.24, 'ACN': 166.89, 'FB': 208.09}

总结

Python 程序中的字典跟现实生活中字典非常像,允许我们以键值对的形式保存数据,再通过键索引对应的值。这是一种非常* *有利于数据检索**的数据类型。再次提醒大家注意,字典中的键必须是不可变类型,字典中的值可以是任意类型。