- 教程
- 文档
【免费下载链接】Python-100-Days
Python - 100天从新手到大师
本篇技术指南以《Python-100-Days》第 13 天内容为核心,系统讲解 Python 字典(dict)这一核心容器类型:从为什么列表、元组、集合都无法胜任"为真实事物建模",到字典的创建方式、键值对约束、成员/索引运算、常用方法与合并技巧,再到字母统计与股票筛选两个实战案例。读者学完本篇后,将掌握字典的完整 API 用法,并能在编程中熟练用字典组织与管理关联数据。
为什么需要字典:列表、元组、集合都不够好
迄今为止,我们已经学习了 Python 中的三种容器型数据类型(列表、元组、集合),但是这些数据类型仍然不足以帮助我们解决所有问题。例如,我们需要一个变量来保存一个人的多项信息,包括:姓名、年龄、身高、体重、家庭住址、本人手机号、紧急联系人手机号。此时你会发现,之前学过的列表、元组和集合类型都不够好使:
person1 = ['王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877'] person2 = ('王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877') person3 = {'王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877'}集合肯定是最不合适的,因为集合中不能有重复元素,如果一个人的年龄和体重刚好相同,那么集合中就会少一项信息;同理,如果这个人的手机号和紧急联系人手机号是相同的,那么集合中又会少一项信息。集合的互异性这一特性决定了它无法用于保存可能重复的字段。关于集合类型的更多细节,可以参考前一天的课程《常用数据结构之集合》。
另一方面,虽然列表和元组可以把一个人的所有信息都保存下来,但是当你想要获取这个人的手机号或家庭住址时,你得先知道他的手机号是列表或元组中的第几个元素——这种"按位置取数据"的方式既不直观,也难以维护。就像在课程《常用数据结构之列表-1》中掷色子统计点数的例子,需要为每个点数单独声明一个变量,一旦数据维度变多,代码会迅速失控。
总之,在遇到上述场景时,列表、元组、集合都不是最合适的选择,此时我们需要字典(dictionary)类型。这种数据类型最适合把相关联的信息组装到一起,可以帮助我们解决 Python 程序中为真实事物建模的问题。
说到字典这个词,大家一定不陌生,读小学的时候,每个人手头基本上都有一本《新华字典》。Python 程序中的字典跟现实生活中的字典很像,它以键值对(键和值的组合)的方式把数据组织到一起,我们可以通过键找到与之对应的值并进行操作。就像《新华字典》中,每个字(键)都有与它对应的解释(值)一样,每个字和它的解释合在一起就是字典中的一个条目,而字典中通常包含了很多个这样的条目。
创建和使用字典
使用{}字面量语法创建字典
Python 中创建字典可以使用{}字面量语法,这一点跟上一节课讲的集合是一样的。但是字典的{}中的元素是以键值对的形式存在的,每个元素由:分隔的两个值构成,:前面是键,:后面是值。需要特别留意:没有元素的{}并不是空集合而是一个空字典,这是集合与字典在字面量语法上的关键区别(详见《常用数据结构之集合》)。
xinhua = { '麓': '山脚下', '路': '道,往来通行的地方;方面,地区:南~货,外~货;种类:他俩是一~人', '蕗': '甘草的别名', '潞': '潞水,水名,即今山西省的浊漳河;潞江,水名,即云南省的怒江' } print(xinhua) person = { 'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101', 'tel': '13122334455', 'emergence contact': '13800998877' } print(person)通过上面的代码,相信大家已经看出来了,用字典来保存一个人的信息远远优于使用列表或元组,因为我们可以用:前面的键来表示条目的含义,而:后面就是这个条目所对应的值。键就像"字段名",值就像"字段值",读代码的人不需要数下标就能明白每项数据代表什么。
使用dict构造器与字典生成式创建字典
除了字面量语法,也可以使用内置函数dict(准确说是创建字典对象的构造器)或字典的生成式语法来创建字典:
# dict函数(构造器)中的每一组参数就是字典中的一组键值对 person = dict(name='王大锤', age=55, height=168, weight=60, addr='成都市武侯区科华北路62号1栋101') print(person) # {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'} # 可以通过Python内置函数zip压缩两个序列并创建字典 items1 = dict(zip('ABCDE', '12345')) print(items1) # {'A': '1', 'B': '2', 'C': '3', 'D': '4', 'E': '5'} items2 = dict(zip('ABCDE', range(1, 10))) print(items2) # {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5} # 用字典生成式语法创建字典 items3 = {x: x ** 3 for x in range(1, 6)} print(items3) # {1: 1, 2: 8, 3: 27, 4: 64, 5: 125}上面用到的zip函数会把两个可迭代对象中的元素按位置一一配对组装成元组,dict接受这些二元组即可生成字典。注意items2的结果只保留了前 5 个元素,因为zip生成的元素个数由较短的可迭代对象决定,这是zip函数的一个重要行为特征,在《Python容器使用小技巧》中也有详细说明。dict构造器还支持直接接收键值对序列或另一个字典,是数据转换时非常常用的入口。
查看长度与遍历字典
想知道字典中一共有多少组键值对,仍然是使用len函数;如果想对字典进行遍历,可以用for循环,但是需要注意,for循环只是对字典的键进行了遍历,不过没关系,在学习了字典的索引运算后,我们可以通过字典的键访问它对应的值。
person = { 'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101' } print(len(person)) # 5 for key in person: print(key)字典的运算
键必须是不可变类型
对于字典类型来说,成员运算和索引运算肯定是很重要的,前者可以判定指定的键在不在字典中,后者可以通过键访问对应的值或者向字典中添加新的键值对。值得注意的是,字典的索引不同于列表的索引:列表中的元素因为有属于自己的有序号,所以列表的索引是一个整数;字典中因为保存的是键值对,所以字典需要用键去索引对应的值。
需要特别提醒大家注意的是,字典中的键必须是不可变类型,例如整数(int)、浮点数(float)、字符串(str)、元组(tuple)等类型,这一点跟集合类型对元素的要求是一样的(集合中的元素必须是hashable类型,详见《常用数据结构之集合》)。很显然,之前我们讲的列表(list)和集合(set)不能作为字典中的键,字典类型本身也不能再作为字典中的键,因为字典也是可变类型。但是列表、集合、字典都可以作为字典中的值,例如:
person = { 'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': ['成都市武侯区科华北路62号1栋101', '北京市西城区百万庄大街1号'], 'car': { 'brand': 'BMW X7', 'maxSpeed': '250', 'length': 5170, 'width': 2000, 'height': 1835, 'displacement': 3.0 } } print(person)上面的addr对应一个列表(一个人的多个住址),car对应一个嵌套字典(一辆车的多项属性),这种"值可以是任意类型、键必须不可变"的规则让字典既能表达复杂结构,又能保证通过键快速定位值。从实现原理看,这与哈希存储有关:键必须能够计算出确定的哈希码,可变类型的哈希码不稳定,因此不能作为键。
成员运算与索引运算
person = {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'} # 成员运算 print('name' in person) # True print('tel' in person) # False # 索引运算 print(person['name']) print(person['addr']) person['age'] = 25 person['height'] = 178 person['tel'] = '13122334455' person['signature'] = '你的男朋友是一个盖世垃圾,他会踏着五彩祥云去迎娶你的闺蜜' print(person) # 循环遍历 for key in person: print(f'{key}:\t{person[key]}')通过索引运算person['age'] = 25可以更新已有键的值,person['tel'] = '13122334455'和person['signature'] = ...则是在字典中添加新的键值对(键不存在时索引运算赋值会新增条目)。需要注意,在通过索引运算获取字典中的值时,如指定的键没有在字典中,将会引发KeyError异常。例如person['sex']会直接报错,因为字典中并没有'sex'这个键。
字典的方法
字典类型的方法基本上都跟字典的键值对操作相关。
get方法:安全获取值
get方法可以通过键来获取对应的值。跟索引运算不同的是,get方法在字典中没有指定的键时不会产生异常,而是返回None或指定的默认值:
person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'} print(person.get('name')) # 王大锤 print(person.get('sex')) # None print(person.get('sex', True)) # Trueperson.get('sex', True)中的第二个参数True就是默认值:键存在时返回该键对应的值,键不存在时返回默认值。这个"取不到就返回默认值"的语义在统计类场景中极其常用(见下文例子 1 中的counter.get(ch, 0))。
keys/values/items方法:遍历字典
如果需要获取字典中所有的键,可以使用keys方法;如果需要获取字典中所有的值,可以使用values方法。字典还有一个名为items的方法,它会将键和值组装成二元组,通过该方法来遍历字典中的元素也是非常方便的:
person = {'name': '王大锤', 'age': 25, 'height': 178} print(person.keys()) # dict_keys(['name', 'age', 'height']) print(person.values()) # dict_values(['王大锤', 25, 178]) print(person.items()) # dict_items([('name', '王大锤'), ('age', 25), ('height', 178)]) for key, value in person.items(): print(f'{key}:\t{value}')可以看到keys、values、items返回的分别是dict_keys、dict_values、dict_items视图对象,它们可以用于遍历,items返回的每个元素都是(键, 值)形式的二元组,配合for key, value in ...的元组解包写法,可以一次拿到键和值。这种遍历方式在实际代码中出现频率极高。
update方法与|运算符:合并字典
字典的update方法实现两个字典的合并操作。例如,有两个字典x和y,当执行x.update(y)操作时,x跟y相同的键对应的值会被y中的值更新,而y中有但x中没有的键值对会直接添加到x中:
person1 = {'name': '王大锤', 'age': 55, 'height': 178} person2 = {'age': 25, 'addr': '成都市武侯区科华北路62号1栋101'} person1.update(person2) print(person1) # {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}如果使用 Python 3.9 及以上的版本,也可以使用|运算符来完成同样的操作,person1 |= person2等价于person1 = person1 | person2,也等价于person1.update(person2):
person1 = {'name': '王大锤', 'age': 55, 'height': 178} person2 = {'age': 25, 'addr': '成都市武侯区科华北路62号1栋101'} person1 |= person2 print(person1) # {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}说明:
|运算符合并字典是 Python 3.9 新增的语法特性,如果运行环境是更早的 Python 版本,请继续使用update方法。
pop/popitem/clear与del:删除操作
可以通过pop或popitem方法从字典中删除元素:前者会返回(获得)键对应的值,但是如果字典中不存在指定的键,会引发KeyError错误;后者在删除元素时,会返回(获得)键和值组成的二元组。字典的clear方法会清空字典中所有的键值对:
person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'} print(person.pop('age')) # 25 print(person) # {'name': '王大锤', 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'} print(person.popitem()) # ('addr', '成都市武侯区科华北路62号1栋101') print(person) # {'name': '王大锤', 'height': 178} person.clear() print(person) # {}跟列表一样,从字典中删除元素也可以使用del关键字,在删除元素的时候如果指定的键索引不到对应的值,一样会引发KeyError错误:
person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'} del person['age'] del person['addr'] print(person) # {'name': '王大锤', 'height': 178}小结一下删除相关的 API:pop(key)需要指定键并返回被删键对应的值;popitem()不指定键,弹出最后一组键值对并返回二元组;clear()清空整个字典;del person[key]直接按键删除但不返回值。前三种是字典类型的方法,del是通用的删除语法(同样适用于列表等可变容器)。
字典的应用
我们通过几个简单的例子来看看如何使用字典类型解决一些实际的问题。
例子 1:统计英文字母出现次数
需求:输入一段话,统计每个英文字母出现的次数,按出现次数从高到低输出。
sentence = input('请输入一段话: ') counter = {} for ch in sentence: if 'A' <= ch <= 'Z' or 'a' <= ch <= 'z': counter[ch] = counter.get(ch, 0) + 1 sorted_keys = sorted(counter, key=counter.get, reverse=True) for key in sorted_keys: 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 次.这个例子完美诠释了"键值对 +get默认值"的组合威力:counter[ch] = counter.get(ch, 0) + 1一行代码就完成了"该字母首次出现则计数为 1,再次出现则累加"的逻辑,无需事先判断键是否存在。sorted(counter, key=counter.get, reverse=True)则利用sorted函数的key参数,按字母出现次数(值)对键进行降序排序——这也是《Python容器使用小技巧》中"从字典中取最大/排序"思想的直接应用。
例子 2:筛选符合条件的股票
需求:在一个字典中保存了股票的代码和价格,找出股价大于 100 元的股票并创建一个新的字典。
说明:可以用字典的生成式语法来创建这个新字典。
stocks = { 'AAPL': 191.88, 'GOOG': 1186.96, 'IBM': 149.24, 'ORCL': 48.44, 'ACN': 166.89, 'FB': 208.09, 'SYMC': 21.29 } stocks2 = {key: value for key, value in stocks.items() if value > 100} print(stocks2)输出:
{'AAPL': 191.88, 'GOOG': 1186.96, 'IBM': 149.24, 'ACN': 166.89, 'FB': 208.09}字典生成式的语法结构为{键表达式: 值表达式 for 键, 值 in 字典.items() if 条件}:先用items()同时取出键和值,再通过if条件完成过滤,最终生成一个新字典。这种写法把"遍历 + 过滤 + 构建新容器"浓缩为一行,代码既简洁又高效。类似的生成式思路在整个课程中反复出现,例如《常用数据结构之集合》中的{num for num in range(1, 20) if num % 3 == 0 or num % 7 == 0},只不过集合生成式只有元素表达式,而字典生成式需要同时给出键和值。
总结
Python 程序中的字典跟现实生活中的字典非常像,允许我们以键值对的形式保存数据,再通过键访问对应的值。字典是一种非常有利于数据检索的数据类型,核心要点如下:
- 创建方式有三种:
{}字面量语法、dict构造器(配合zip或关键字参数)、字典生成式; - 键必须是不可变类型(
int、float、str、tuple等),列表、集合、字典等可变类型的数据都不能作为字典的键,但都可以作为值; - 成员运算
in/not in判断键是否存在;索引运算dict[key]取值、改值、加条目,键不存在时取值会引发KeyError; - 常用方法:
get(安全取值,支持默认值)、keys/values/items(遍历键、值、键值对)、update(合并,Python 3.9+ 可用|)、pop/popitem/clear/del(删除); - 实战场景:利用"键值对 +
get默认值"做计数统计,利用字典生成式做条件筛选。
学完字典之后,Python 的四种容器型数据类型(列表、元组、集合、字典)就已经齐了,它们各自有不同的适用场景:列表适合有序且允许重复的序列,元组适合不可变的有序序列,集合适合无序且去重的元素集合,字典则适合通过键快速检索关联数据。在后续课程中——无论是函数参数传递(详见《函数和模块》)、面向对象编程(详见《面向对象编程入门》),还是更后面的文件读写、数据分析、Web 开发——字典都将成为最常用的数据类型之一,掌握好本课的 API 与建模思路,是迈向"用 Python 为真实世界建模"的关键一步。
- 教程
- 文档
【免费下载链接】Python-100-Days
Python - 100天从新手到大师
相关推荐
免费音乐歌词获取终极指南:三步快速下载网易云QQ音乐LRC歌词
免费音乐歌词获取终极指南:三步快速下载网易云QQ音乐LRC歌词 还在为找不到心爱歌曲的歌词而烦恼吗?当你听到一首动人的旋律却无法跟着唱,当你想理解外语歌词却找不
桌面应用音视频Python 100 天学习笔记:常用数据结构之字符串的表示、运算与内置方法
Python 100 天学习笔记:常用数据结构之字符串的表示、运算与内置方法 导读 本篇技术指南是《Python 100 Days》第 11 天的核心内容,聚焦
教程文档Python 100天从新手到大师:完整学习路线图,轻松掌握编程技能
Python 100天从新手到大师:完整学习路线图,轻松掌握编程技能 想要在100天内从Python新手成长为编程大师吗?这个完整的Python学习指南为你提供
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考