返回文章列表

文章

defaultdict 的用法

defaultdict 是对内置 dict 的一个简单封装,它的核心特性就是:当你访问或写入一个不存在的键时,不会抛出 KeyError,而是自动地为它创建一个“默认值”

目录
  1. 在 Python 的 collections 模块里,defaultdict 是对内置 dict 的一个简单封装,它的核心特性就是:当你访问或写入一个不存在的键时,不会抛出 KeyError,而是自动地为它创建一个“默认值”。这个默认值由你在构造 defaultdict 时传入的“工厂函数”(default_factory)来生成。 下面我从几个方面详细拆解它的行为和用法。
  2. 1. 基本用法
  3. 2. 对比普通 dict + setdefault
  4. 3. 常见的几种 default_factory
  5. 4. 在 merge_dict_data 中的作用
  6. 代码更简洁,也更高效(少一次函数调用和一次写字典操作)。
  7. 5. 转回普通 dict
  8. 这样就把它“解包”成纯粹的 dict,相当于复制了一份键值对到一个新 dict 里。
  9. 小结

在 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#

  1. list
    • 最常见 用于分组、累加列表项,见下面示例。
  2. set
    • 如果要自动去重或构造集合,就用 defaultdict(set)
  3. 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 是非常常用的利器。