Dictionary
Perspective
Python dictionary(dict)是最常用的数据结构之一。它保存的是键到值的映射:用一个 key 快速找到对应的 value。
读代码时先记住一句话:字典适合表达“某个名字、编号或标签对应什么东西”。 如果数据天然是一组有名字的字段、计数、配置、查找表或分组结果,dict 往往比 list 更直接。
Definition
A dictionary is a mutable mapping from hashable keys to values.
中文理解:字典是一个可修改的映射表。每个元素由 key: value 组成,key 必须是可哈希对象,value 可以是任意对象。
person = {
"name": "Alice",
"age": 30,
"city": "Shanghai",
}这里 "name"、"age"、"city" 是 key;"Alice"、30、"Shanghai" 是对应的 value。
Basic Operations
Create
scores = {"Alice": 92, "Bob": 85}
empty = {}Read
scores["Alice"]如果 key 不存在,scores["Carol"] 会抛出 KeyError。不确定 key 是否存在时,用 get() 更稳妥:
scores.get("Carol", 0)Add or update
scores["Carol"] = 88
scores["Alice"] = 95同一个 key 只能出现一次。再次赋值会覆盖旧值。
Delete
del scores["Bob"]Check membership
"Alice" in scores注意:in 检查的是 key,不是 value。
Iteration
默认遍历字典时,得到的是 key:
for name in scores:
print(name)常见的三种遍历方式:
for key in scores.keys():
print(key)
for value in scores.values():
print(value)
for key, value in scores.items():
print(key, value)实际写代码时,items() 很常用,因为它同时给出 key 和 value。
Common Patterns
Counting
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1Lookup table
cell_type_color = {
"T cell": "blue",
"B cell": "green",
"Macrophage": "red",
}Structured record
sample = {
"sample_id": "S001",
"condition": "treated",
"n_cells": 12043,
}Grouping
groups = {}
for sample in samples:
condition = sample["condition"]
groups.setdefault(condition, []).append(sample)这种写法等价于 collections.defaultdict(list),后者读起来更直接,少一层 setdefault 的认知负担。
Key Rules
字典的 key 必须是 hashable。常见可作为 key 的类型包括:
- string
- number
- tuple containing only hashable values
- boolean
list、dict、set 不能作为 key,因为它们是 mutable objects。
还有一个容易忽略的小坑:True == 1 且 hash(True) == hash(1),所以 {True: "a", 1: "b"} 在字典里只会留下一项(后者覆盖前者)。布尔值和整数混用作为 key 时要留意。
valid = {("A", 1): "sample A1"}
invalid = {
["A", 1]: "sample A1" # TypeError: unhashable type: 'list'
}第二个例子会报错,因为 list 不能作为字典 key。
Reading Cautions
dict是 mutable object。把同一个字典传给函数后,函数内部修改会影响原对象。d[key]适合确定 key 存在的情况;不确定时用d.get(key)或先判断key in d。in判断 key 是否存在,不判断 value。同一个 key 重复赋值时,后面的 value 会覆盖前面的 value。
字典保留插入顺序,但不要把它当成排序结构;需要排序时显式使用
sorted()。用 mutable default value 构造嵌套字典时要小心,多个 key 共享同一个 list 或 dict 会产生难查的 bug。例如:
d = dict.fromkeys(["a", "b", "c"], []) d["a"].append(1) # d 现在是 {"a": [1], "b": [1], "c": [1]},三个 key 指向同一个 list正确做法是用
collections.defaultdict(list),或显式为每个 key 创建独立的 list。
Note
对我来说,读 Python 字典最重要的是先判断它在代码中扮演什么角色:是一个 record、lookup table、counter,还是 grouping container。角色不同,应该关注的点也不同。record 要看字段名是否清楚;lookup table 要看 key 覆盖是否完整;counter 要看默认值;grouping container 要看 list 或 dict 是否被意外共享。