好的,以下是完整详细的【Python】深入了解 defaultdict 的专题教程,适合从基础到进阶地掌握它的使用方法、原理及在复杂数据结构中的实战技巧。


📘 教程目录

  1. 什么是 defaultdict
  2. 为什么要用 defaultdict 而不是 dict
  3. defaultdict 的基本用法
  4. 常见默认工厂函数示例(list、int、set 等)
  5. 多层嵌套字典结构的构建
  6. 与 Counter 和 groupby 等结合使用
  7. 使用 lambda 和自定义函数作为默认工厂
  8. 注意事项与陷阱
  9. 实战案例:
    • 单词频率统计
    • 图的邻接表建模
    • 多维嵌套字典管理 JSON 数据
  10. 总结与推荐实践

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. 与 Countergroupby 结合使用

单词频率统计:

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 或函数