文章
defaultdict 的用法
defaultdict 是对内置 dict 的一个简单封装,它的核心特性就是:当你访问或写入一个不存在的键时,不会抛出 KeyError,而是自动地为它创建一个“默认值”
目录
- 在 Python 的 collections 模块里,defaultdict 是对内置 dict 的一个简单封装,它的核心特性就是:当你访问或写入一个不存在的键时,不会抛出 KeyError,而是自动地为它创建一个“默认值”。这个默认值由你在构造 defaultdict 时传入的“工厂函数”(default_factory)来生成。 下面我从几个方面详细拆解它的行为和用法。
- 1. 基本用法
- 2. 对比普通 dict + setdefault
- 3. 常见的几种 default_factory
- 4. 在 merge_dict_data 中的作用
- 代码更简洁,也更高效(少一次函数调用和一次写字典操作)。
- 5. 转回普通 dict
- 这样就把它“解包”成纯粹的 dict,相当于复制了一份键值对到一个新 dict 里。
- 小结
在 Python 的 collections 模块里,defaultdict 是对内置 dict 的一个简单封装,它的核心特性就是:当你访问或写入一个不存在的键时,不会抛出 KeyError,而是自动地为它创建一个“默认值”。这个默认值由你在构造 defaultdict 时传入的“工厂函数”(default_factory)来生成。
下面我从几个方面详细拆解它的行为和用法。#
1. 基本用法#
from collections import defaultdict
# 创建一个当访问不存在键时,默认生成空列表的 defaultdict
dd = defaultdict(list)
# 访问一个还没存过的键
print(dd['foo']) # 输出:[],而不是 KeyError
print(dd) # 输出:defaultdict(<class 'list'>, {'foo': []})
default_factory=list:当你写dd['foo']而'foo'不在字典中,defaultdict就会自动做等同于dd['foo'] = list(),即把一个新的空列表当作值放进去,然后把它返回给你。
2. 对比普通 dict + setdefault#
# 普通 dict
d = {}
# d['foo'] # 这行会抛 KeyError
# 若要模拟 defaultdict,需要写:
d.setdefault('foo', [])
print(d['foo']) # []
setdefault每次都要传入默认值,还要执行一次函数调用并写回字典。defaultdict则把“默认值的产生”封装到default_factory,每次访问未知键时自动触发。- 可读性更好、也更少出错。
3. 常见的几种 default_factory#
list- 最常见 用于分组、累加列表项,见下面示例。
set- 如果要自动去重或构造集合,就用
defaultdict(set)。
- 如果要自动去重或构造集合,就用
int- 默认值为
0,适合做计数器:
- 默认值为
counter = defaultdict(int)
for word in words:
counter[word] += 1
4. **自定义工厂** - 你也可以传入任何无参可调用对象,比如一个返回复杂结构的新函数: python
def make_user_record():
return {'visits': 0, 'last_seen': None}
users = defaultdict(make_user_record)
```
4. 在 merge_dict_data 中的作用#
在我们的合并函数中,用到了:
merged: defaultdict[str, list[T]] = defaultdict(list)
seen: defaultdict[str, set[T]] = defaultdict(set)
merged[key]- 第一次写
merged[key].append(item)时,如果key还不存在,defaultdict(list)会先执行list(),把一个空列表放到merged[key],然后再做.append(item)。
- 第一次写
seen[key]- 同理,第一次访问时会先创建一个空的
set()。 这样我们就 不必 在每次循环里写:
- 同理,第一次访问时会先创建一个空的
merged.setdefault(key, [])
seen.setdefault(key, set())
代码更简洁,也更高效(少一次函数调用和一次写字典操作)。#
5. 转回普通 dict#
虽然 defaultdict 在构建过程中很方便,但如果其他代码期望收到一个普通 dict,我们可以在函数最后写:
return dict(merged)
这样就把它“解包”成纯粹的 dict,相当于复制了一份键值对到一个新 dict 里。#
小结#
defaultdict的关键在于default_factory,它决定了“缺失键”时插入什么样的默认值。- 它省去对
setdefault的调用,让代码简洁、可读性强,也常常有微量的性能提升。 - 在「聚合分组」「去重计数」「递归合并」等场景里,
defaultdict是非常常用的利器。