好的,以下是完整详细的【Python】深入了解 defaultdict
的专题教程,适合从基础到进阶地掌握它的使用方法、原理及在复杂数据结构中的实战技巧。
📘 教程目录
- 什么是
defaultdict
? - 为什么要用
defaultdict
而不是dict
? defaultdict
的基本用法- 常见默认工厂函数示例(list、int、set 等)
- 多层嵌套字典结构的构建
- 与
Counter
和groupby
等结合使用 - 使用
lambda
和自定义函数作为默认工厂 - 注意事项与陷阱
- 实战案例:
- 单词频率统计
- 图的邻接表建模
- 多维嵌套字典管理 JSON 数据
- 总结与推荐实践
1. 什么是 defaultdict
?
defaultdict
是 collections
模块中的一个子类,继承自 dict
,可以自动为不存在的键生成默认值,避免 KeyError
。
2. 为什么要用 defaultdict
?
普通 dict
在访问一个不存在的键时会报错:
d = {}
print(d['x']) # KeyError
而 defaultdict
会自动插入默认值:
from collections import defaultdict
d = defaultdict(int)
print(d['x']) # 输出 0
3. defaultdict
的基本用法
from collections import defaultdict
# 使用 int 作为默认工厂,所有新键默认为 0
count = defaultdict(int)
count['apple'] += 1
count['banana'] += 1
print(count) # {'apple': 1, 'banana': 1}
4. 常见默认工厂函数
默认工厂 | 含义与应用 |
---|---|
int | 默认值为 0,适合计数场景 |
list | 默认值为空列表,适合分组、聚合 |
set | 默认值为空集合,适合去重操作 |
str | 默认值为空字符串 |
示例:
group = defaultdict(list)
group['python'].append('Guido')
group['python'].append('Raymond')
print(group) # {'python': ['Guido', 'Raymond']}
5. 多层嵌套字典结构的构建
传统写法非常繁琐:
data = {}
if 'a' not in data:
data['a'] = {}
if 'b' not in data['a']:
data['a']['b'] = 0
data['a']['b'] += 1
用 defaultdict
一步搞定:
from collections import defaultdict
data = defaultdict(lambda: defaultdict(int))
data['a']['b'] += 1
print(data) # {'a': {'b': 1}}
6. 与 Counter
、groupby
结合使用
单词频率统计:
from collections import defaultdict
text = "to be or not to be"
word_freq = defaultdict(int)
for word in text.split():
word_freq[word] += 1
print(word_freq) # {'to': 2, 'be': 2, 'or': 1, 'not': 1}
按部门分组员工:
employees = [('HR', 'Alice'), ('IT', 'Bob'), ('HR', 'Eve')]
grouped = defaultdict(list)
for dept, name in employees:
grouped[dept].append(name)
print(grouped) # {'HR': ['Alice', 'Eve'], 'IT': ['Bob']}
7. 使用 lambda
或自定义工厂函数
d = defaultdict(lambda: "未知")
print(d["不存在"]) # 输出 "未知"
也可以使用复杂结构:
def my_factory():
return {'count': 0, 'values': []}
d = defaultdict(my_factory)
d['A']['count'] += 1
d['A']['values'].append(42)
8. 注意事项与陷阱
- 一旦访问不存在的键,就会自动创建它,即使你只是调试查看:
d = defaultdict(int)
print('z' in d) # False
print(d['z']) # 0
print('z' in d) # True
- 无法序列化为 JSON(需要先转成普通 dict)
import json
json.dumps(dict(d)) # 正确
json.dumps(d) # TypeError
9. 实战案例
🧪 案例 1:图结构 – 邻接表建模
graph = defaultdict(list)
graph['A'].append('B')
graph['A'].append('C')
graph['B'].append('D')
# {'A': ['B', 'C'], 'B': ['D']}
🧪 案例 2:嵌套多层 JSON 数据合并
nested = defaultdict(lambda: defaultdict(list))
nested['user1']['logs'].append("Login")
nested['user1']['logs'].append("View page")
10. 总结与推荐实践
场景 | 建议默认工厂 |
---|---|
计数器 | int |
分组聚合 | list |
图的邻接表 | list |
多层嵌套结构 | 嵌套 defaultdict |
自定义结构 | lambda 或函数 |
发表回复