Python编程基础之字典
前言刚开始学 Python 的人常会问列表list已经能存一串数据了为什么还要学字典答案藏在一个很具体的场景里——当你要保存的是「成对」的数据比如每门课对应一个分数、每个人对应一个电话列表就不够用了。用列表硬凑成对数据通常得开两个列表一个存「名字」一个存「分数」靠下标位置对齐。位置一旦错位数据就会张冠李戴而且查一个名字要先遍历找下标非常别扭。字典正是为这种「一对一」关系设计的它存的不是单个元素而是一个个键值对key-value pair。本文是零基础入门篇只讲最基础的概念和四个动作建、查、改、加。不涉及哈希表原理、不提defaultdict、不碰合并运算符保证每一步都能照着写下来。所有示例用 Python 3 编写。一、先看看没有字典时的麻烦假设要记录三个同学的年龄用列表只能这样# 适用于 Python 3.8names [小明, 小红, 小刚]ages [18, 19, 17]# 想查小红的年龄得先找下标i names.index(小红)print(ages[i]) # 19这段代码能跑但问题很明显两个列表必须始终保持长度一致、顺序一致。如果哪天有人只往names里加了一个人而忘了同步ages第 3 个同学的年龄就会对到第 4 个名字上。数据一多这种错误几乎无法避免。二、键值对是什么字典把「名字」和「年龄」放在同一条记录里绑死在一起# 适用于 Python 3.8ages {小明: 18, 小红: 19, 小刚: 17}花括号里的每一项都是键: 值。小明是键key18是值value冒号把它们连成一对逗号分隔不同的对。这样「小明」和 18 就再也不会被拆散了。读起来也直观键是「拿什么去查」值是「查出来的结果」。键必须唯一值可以重复——两个人可以有同样的年龄但不能有两个人共用同一个名字当键真重复了后面的会覆盖前面的。三、最基础的四个动作学字典先记住四件事建、查、改、加。建就是写花括号。想建一个空字典写{}或dict()。# 适用于 Python 3.8empty {} # 空字典ages {小明: 18, 小红: 19}print(len(ages)) # 2查是用方括号把键放进去# 适用于 Python 3.8ages {小明: 18, 小红: 19}print(ages[小明]) # 18查的时候键必须存在否则会报KeyError。不确定键在不在可以用in先问一句或者用get()# 适用于 Python 3.8ages {小明: 18}print(小明 in ages) # Trueprint(小刚 in ages) # Falseprint(ages.get(小刚, 0)) # 0键不在就返回给出的默认值改和加用的是同一句写法d[键] 值。键原来在就是改原来不在就是加。# 适用于 Python 3.8ages {小明: 18}ages[小明] 19 # 键存在 → 改ages[小刚] 17 # 键不存在 → 加print(ages) # {小明: 19, 小刚: 17}删除用del# 适用于 Python 3.8ages {小明: 18, 小红: 19}del ages[小红]print(ages) # {小明: 18}四、小例子一个电话簿把上面的动作串起来写一个能增、能查、能删的简易电话簿# 适用于 Python 3.8phonebook {}def add(name, number):phonebook[name] numberdef find(name):# 找不到时返回一句提示而不是让程序崩掉return phonebook.get(name, 查无此人)def remove(name):phonebook.pop(name, None) # 第二个参数表示「没有也不报错」add(小明, 138-0000-0001)add(小红, 139-0000-0002)print(find(小明)) # 138-0000-0001print(find(小王)) # 查无此人remove(小红)print(phonebook) # {小明: 138-0000-0001}注意pop的第二个参数给了它键不存在时返回它而不报错不给它键不存在就抛KeyError。这和列表里list.pop()不带参数删末尾的行为不同是专门为字典设计的。五、字典和列表怎么选场景用列表用字典一批同类的数据有先后顺序是一般不用一对一查找名字找电话别扭是需要按下标读取是不支持需要按「名字」读取做不到是数据会重复出现可以键不能重复一句话要顺序用列表要对应关系用字典。六、让字典和循环配合起来字典单独的用法很简单真正开始有用是在它和循环配合之后。下面这段把「读取每一项」和「按条件处理」连起来# 适用于 Python 3.8inventory {苹果: 5, 香蕉: 0, 橙子: 3}# 逐个检查有没有缺货for name, count in inventory.items():if count 0:print(name, 缺货了)else:print(name, 剩, count, 个)items()一次给出「键」和「值」两个变量name拿到键、count拿到值。这是遍历字典最常用的写法。如果只关心键写for name in inventory:就行只关心值则写for count in inventory.values():。再进一步可以一边遍历一边把结果收集到新字典里# 适用于 Python 3.8prices {苹果: 3, 香蕉: 2, 橙子: 4}doubled {}for name, price in prices.items():doubled[name] price * 2 # 放进一个新字典print(doubled) # {苹果: 6, 香蕉: 4, 橙子: 8}这里doubled[name] price * 2用的是最基本的赋值新字典里没有这个键就当作新增已经有了就覆盖。循环里一个写法既能新增又能更新正是字典方便的地方。常见坑点坑一把不存在的键当普通下标查。# 适用于 Python 3.8# ❌ 键没写对就崩d {小明: 18}print(d[小明 ]) # 多了一个空格 → KeyError# ✅ 不确定时用 get() 兜底print(d.get(小明 )) # None坑二以为in判断的是值。# 适用于 Python 3.8# ❌ in 只看键不看值d {小明: 18}print(18 in d) # False容易看错# ✅ 要判断值就先取出来print(18 in d.values()) # True坑三键和值的位置写反。# 适用于 Python 3.8# ❌ 想用名字查年龄却把年龄写成了键d {18: 小明}print(d[小明]) # KeyError: 小明# ✅ 拿什么去查什么就放在冒号左边d {小明: 18}print(d[小明]) # 18坑四键的拼写不一致悄悄变成两条记录。# 适用于 Python 3.8# ❌ name 和 Name 是两个不同的键d {}d[name] 小明d[Name] 小红print(d) # {name: 小明, Name: 小红}# ✅ 统一拼写规范d {name: 小明}坑五重复的键以为能都留下。# 适用于 Python 3.8# ❌ 同一个键后写会覆盖前面d {a: 1, a: 2}print(d) # {a: 2}# ✅ 值本身要多个就存一个列表d {a: [1, 2]}坑六想加一项却用了列表的append。# 适用于 Python 3.8# ❌ 字典没有 appendd {}d.append((a, 1)) # AttributeError: dict object has no attribute append# ✅ 加一项就是给它一个键值d[a] 1print(d) # {a: 1}坑七整数键和字符串键混用。# 适用于 Python 3.8# ❌ 1 和 1 是两个不同的键d {1: 数字一}d[1] 字符串一print(d) # {1: 数字一, 1: 字符串一}# ✅ 统一键的类型别混着用d {1: 数字一}print(len(d)) # 1总结动作写法别名建{键: 值}/{}花括号查d[键]/d.get(键, 默认)后者更安全改d[已存在的键] 新值位置不变加d[新键] 值追加到末尾删del d[键]/d.pop(键)pop可带默认值判存在键 in d判断的是键字典的核心就一句话用键去换值。只要记住键必须唯一、d[k]缺键会报错而d.get(k)不会、in判断的是键入门阶段就不会踩大坑。