前言
这篇是一份操作速查:把字典(dict)日常用得到的操作,按「增、删、改、查、遍历」五类摊开,每条给一个最简示例。目标是当作手边的清单——想到要做什么,扫一眼就能找到写法,不用翻长文。
标题里带了个「1」,很多读者会以为还有续篇。这里说明一下:本文是自足的,所有内容一次讲完,不需要也不引用任何其他篇目。后续如果有更进阶的原理篇,那是另一条线,与本文无关。
另外提醒一句:本文示例以 Python 3 为准,涉及 3.9 才有的合并运算符时会单独标注。Python 2 里的iteritems()、has_key()等方法在 Python 3 中已经移除,不要再用。
一、增:往字典里放东西
d.update(other) | 批量合并,已有键被覆盖 |
d.setdefault(k, v) | 键不存在才写入,并返回当前值 |
# 适用于 Python 3.8+
d = {}
d["a"] = 1 # 新增
d.update({"b": 2, "c": 3}) # 批量新增
d.update(d=[4]) # 关键字形式也可
print(d) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
print(d.setdefault("e", 5)) # 5,写入并返回
print(d.setdefault("a", 999)) # 1,已存在就不覆盖,返回原值
update()返回None(原地修改),这点和d1 | d2返回新字典不同。
二、删:从字典里拿掉东西
d.pop(k) | 删除并返回该值;缺键抛KeyError |
d.pop(k, default) | 缺键返回默认值,不抛异常 |
d.popitem() | 弹出最后一个键值对(LIFO) |
# 适用于 Python 3.8+
d = {"a": 1, "b": 2, "c": 3}
del d["a"]
print(d.pop("b")) # 2
print(d.pop("x", None)) # None,缺键不报错
print(d.popitem()) # ('c', 3),从末尾弹出(3.7 起为 LIFO)
d.clear()
print(d) # {}
popitem()从Python 3.7 起保证按 LIFO(后进先出)顺序弹出。
三、改:更新已有内容
# 适用于 Python 3.9+
d = {"a": 1, "b": 2}
d["a"] = 100 # 覆盖
d |= {"b": 200, "c": 300} # 原地合并,右键优先
print(d) # {'a': 100, 'b': 200, 'c': 300}
Python 3.9 之前没有|=,等价写法是d.update(other)。
四、查:读值、判存在
d.get(k, default) | 返回default |
# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
print(d["a"]) # 1
print(d.get("z")) # None
print(d.get("z", 0)) # 0
print("a" in d) # True,判断键
print(len(d)) # 2
再强调一次:d["z"]会崩,d.get("z")不会。这两者不是同一件事。
五、遍历:把字典走一遍
# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
for k in d:
print(k) # a, b
for k, v in d.items():
print(k, v) # a 1 / b 2
print(list(d.keys())) # ['a', 'b']
print(list(d.values())) # [1, 2]
print(list(reversed(d))) # ['b', 'a'],需要 Python 3.8+
视图是动态的:字典改了,视图跟着变。
# 适用于 Python 3.8+
d = {"a": 1}
it = d.items()
d["b"] = 2
print(list(it)) # [('a', 1), ('b', 2)]
六、几条速记规则
- 键必须可哈希:字符串、数字、元组可以;列表、字典、集合不行。
- 值可以重复,键不能重复;重复赋值以最后一次为准。
- 3.7 起字典保持插入顺序;更新已有键不改顺序,删除后重插会排到末尾。
- 判断存在用
in,它只看键。
- 遍历时别增删键,否则可能抛
RuntimeError。
七、几个常用组合写法
下面这些是字典操作里出现频率很高的小组合,可以当速查的补充。
按值排序,取前几名。
# 适用于 Python 3.8+
scores = {"数学": 95, "语文": 88, "英语": 79}
top = sorted(scores.items(), key=lambda kv: kv[1], reverse=True)
print(top) # [('数学', 95), ('语文', 88), ('英语', 79)]
按值反查键。
# 适用于 Python 3.8+
d = {"a": 3, "b": 7, "c": 5}
print(max(d, key=d.get)) # 'b',值最大的键
反转键值(要求值也不重复、且可哈希)。
# 适用于 Python 3.8+
d = {"a": 1, "b": 2}
inv = {v: k for k, v in d.items()}
print(inv) # {1: 'a', 2: 'b'}
按条件筛选出一部分键值对。
# 适用于 Python 3.8+
d = {"a": 1, "b": 20, "c": 3}
big = {k: v for k, v in d.items() if v > 2}
print(big) # {'b': 20, 'c': 3}
把两个计数结果加起来。
# 适用于 Python 3.8+
from collections import Counter
a = Counter({"x": 1})
b = Counter({"x": 2, "y": 5})
print(a + b) # Counter({'y': 5, 'x': 3})
按白名单挑出部分键。
# 适用于 Python 3.8+
d = {"name": "小明", "age": 18, "secret": "x"}
keep = {"name", "age"}
clean = {k: v for k, v in d.items() if k in keep}
print(clean) # {'name': '小明', 'age': 18}
常见坑点
坑一:get()和pop()的默认值位置混淆。
# 适用于 Python 3.8+
# ❌ 以为 get 的第二个参数是「找不到就设成这个值」
d = {"a": 1}
d.get("b", 5)
print(d) # {'a': 1},get 只是返回 5,不写回字典
# ✅ 要写入用 setdefault
d.setdefault("b", 5)
print(d) # {'a': 1, 'b': 5}
坑二:把update()的返回值当新字典。
# 适用于 Python 3.8+
# ❌ update 原地改,返回 None
d = {"a": 1}
e = d.update({"b": 2})
print(e) # None
# ✅ 想要新字典用合并运算符(3.9+)
e = d | {"b": 2}
print(e) # {'a': 1, 'b': 2}
坑三:update传了一个字符串。
# 适用于 Python 3.8+
# ❌ 字符串会被当成「键值对序列」,单字符凑不成一对
d = {"a": 1}
d.update("xy") # ValueError: 元素长度为 1,需要 2
# ✅ 传映射或二元组序列
d.update({"x": 1, "y": 2})
print(d) # {'a': 1, 'x': 1, 'y': 2}
坑四:用del删一个不存在的键。
# 适用于 Python 3.8+
# ❌ 键不存在时 del 抛 KeyError
d = {"a": 1}
del d["b"] # KeyError: 'b'
# ✅ 用 pop 给个默认值,不存在也不报错
d.pop("b", None)
print(d) # {'a': 1}
坑五:以为popitem()弹第一个。
# 适用于 Python 3.8+
# ❌ 3.7 起 popitem 从末尾弹,是 LIFO
d = {"a": 1, "b": 2}
print(d.popitem()) # ('b', 2)
# ✅ 想弹指定键就用 pop
print(d.pop("a")) # 1
坑六:把视图当快照提前存下来。
# 适用于 Python 3.8+
# ❌ 以为 it 是当时的快照
d = {"a": 1}
it = d.keys()
d["b"] = 2
print(list(it)) # ['a', 'b'],视图会跟着变
# ✅ 要快照就显式复制
snap = list(d.keys())
坑七:以为sorted(d)是按值排序。
# 适用于 Python 3.8+
# ❌ 直接排字典,得到的是「按键排序」
d = {"b": 1, "a": 2}
print(sorted(d)) # ['a', 'b'],排的是键
# ✅ 想按值排,就把 items 取出来指定 key
print(sorted(d.items(), key=lambda kv: kv[1])) # [('b', 1), ('a', 2)]
总结
| 增 | d[k] = v、update、setdefault | setdefault只在缺键时写 |
| 删 | del、pop、popitem、clear | pop可带默认值 |
| 遍历 | keys、values、items | 返回动态视图 |
把这张速查表放在手边,日常的字典操作基本都能覆盖。真正要牢记的只有两点:d[k]与d.get(k)在缺键时行为不同;遍历过程中不要改变字典大小。