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