defaultdict vs dict
## 为什么要用 defaultdict? 这段代码在做**字符和二元组统计**: ```python from collections import defaultdict uni, bi = defaultdict(int), defaultdict(int) for s in ["我爱中国", "我爱学习", "我喜欢中国"]: w = list(s) for c in w: uni[c] += 1 for i in range(len(w)-1): bi[(w[i], w[i+1])] += 1 p = bi[("我","爱")] / uni["我"] # P(爱|我) = count(我,爱)/count(我) ``` ### 核心原因 `defaultdict(int)` 在访问**不存在的键**时,会自动调用 `int()` 返回 `0`,因此: | 操作 | defaultdict | 普通dict | |------|-------------|----------| | 访问新键 | 返回 0 | 抛出 KeyError | | `d[key] += 1` | ✅ 直接用 | ❌ 需先初始化 | ### 关键点 代码中的 `uni[c] += 1` 和 `bi[(w[i], w[i+1])] += 1` 依赖于: 1. 首次访问某字符/二元组时,值自动初始化为 0 2. 然后 0 + 1 = 1 完成首次计数 3. 后续访问正常累加 ### 执行流程示例 以 `uni["我"] += 1` 为例: ```text 第1次访问 uni["我"] → defaultdict返回0 → 0+1=1 存入 第2次访问 uni["我"] → 已存在,值为1 → 1+1=2 存入 第3次访问 uni["我"] → 已存在,值为2 → 2+1=3 存入 ``` 如果用普通 dict,第1次访问会直接报错 `KeyError: '我'`。
## 普通dict的等价写法 如果坚持用普通 dict,需要手动处理键不存在的情况: ### 方式一:显式检查(啰嗦) ```python uni, bi = {}, {} for s in ["我爱中国", "我爱学习", "我喜欢中国"]: w = list(s) for c in w: if c not in uni: uni[c] = 0 uni[c] += 1 for i in range(len(w)-1): key = (w[i], w[i+1]) if key not in bi: bi[key] = 0 bi[key] += 1 ``` ### 方式二:使用 setdefault(稍好) ```python uni, bi = {}, {} for s in ["我爱中国", "我爱学习", "我喜欢中国"]: w = list(s) for c in w: uni[c] = uni.setdefault(c, 0) + 1 for i in range(len(w)-1): key = (w[i], w[i+1]) bi[key] = bi.setdefault(key, 0) + 1 ``` ### 方式三:使用 get(最常见) ```python uni, bi = {}, {} for s in ["我爱中国", "我爱学习", "我喜欢中国"]: w = list(s) for c in w: uni[c] = uni.get(c, 0) + 1 for i in range(len(w)-1): key = (w[i], w[i+1]) bi[key] = bi.get(key, 0) + 1 ``` ### 代码行数对比 | 写法 | 新增行数 | 可读性 | |------|----------|--------| | defaultdict | 0 | ⭐⭐⭐ | | get() | +1变量 | ⭐⭐ | | setdefault() | +1变量 | ⭐⭐ | | 显式检查 | +4行if | ⭐ | **结论**:对于计数、累加这类"访问-修改"操作,defaultdict 是最简洁的选择。
参考