基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

collections 模块中 defaultdict 和普通 dict 有什么区别?

知识点图片

Python 中的 collections.defaultdict 是内置 dict(字典)的一个子类。它们最大的区别在于 如何处理不存在的键(Missing Keys)

以下是详细的对比分析:

1. 核心区别:访问不存在的键

  • 普通 dict

    • 如果你试图访问一个不存在的键(例如 d['key']),Python 会抛出 KeyError 异常。
    • 你需要先检查键是否存在,或者使用 .get() 方法来避免报错。
  • defaultdict

    • 如果你访问一个不存在的键,它 不会报错
    • 相反,它会调用初始化时传入的 default_factory(工厂函数),生成一个默认值,将该值赋给这个键,并返回这个值。

2. 代码对比

让我们通过两个最常见的场景来看看代码写法的不同。

场景 A:计数(Counting)

假设我们要统计一个列表中每个单词出现的次数。

普通 dict 写法:

python
words = ['apple', 'banana', 'apple', 'orange']
counts = {}

for word in words:
    if word in counts:
        counts[word] += 1
    else:
        counts[word] = 1  # 必须手动初始化

# 或者使用 .get()
# counts[word] = counts.get(word, 0) + 1

defaultdict 写法:

python
from collections import defaultdict

words = ['apple', 'banana', 'apple', 'orange']
# int() 函数被调用时返回 0
counts = defaultdict(int) 

for word in words:
    counts[word] += 1  # 不需要检查,直接加
    # 第一次遇到 'apple' 时,counts['apple'] 自动变为 0,然后 +1

场景 B:分组(Grouping)

假设我们要把一个元组列表按类别分组。

普通 dict 写法:

python
data = [('fruit', 'apple'), ('fruit', 'banana'), ('veg', 'carrot')]
grouped = {}

for category, item in data:
    if category not in grouped:
        grouped[category] = []  # 必须手动创建一个空列表
    grouped[category].append(item)

# 或者使用 setdefault
# grouped.setdefault(category, []).append(item)

defaultdict 写法:

python
from collections import defaultdict

data = [('fruit', 'apple'), ('fruit', 'banana'), ('veg', 'carrot')]
# list() 函数被调用时返回空列表 []
grouped = defaultdict(list) 

for category, item in data:
    grouped[category].append(item) # 直接 append,键不存在时自动创建空列表

3. 初始化方式

  • 普通 dict

    python
    d = {}
    # 或
    d = dict()
  • defaultdict
    你需要传入一个可调用的对象(函数或类)作为 default_factory

    python
    from collections import defaultdict
    
    d_int = defaultdict(int)      # 默认值是 0
    d_list = defaultdict(list)    # 默认值是 []
    d_set = defaultdict(set)      # 默认值是 set()
    d_str = defaultdict(str)      # 默认值是 ""
    d_custom = defaultdict(lambda: "Unknown") # 默认值是 "Unknown"

4. defaultdict 的一个潜在陷阱(副作用)

使用 defaultdict 时要小心,只要你访问了一个不存在的键,它就会被创建并加入字典中

python
d = defaultdict(int)
print(d) # defaultdict(<class 'int'>, {})

# 仅仅是打印或检查某个键
print(d['non_existent_key']) 

# 此时字典里已经多了一个键!
print(d) # defaultdict(<class 'int'>, {'non_existent_key': 0})

而在普通 dict 中,如果你使用 d.get('key'),虽然返回 None,但不会改变字典本身。

5. 总结

特性 普通 dict collections.defaultdict
访问不存在的键 抛出 KeyError 调用工厂函数生成默认值,不报错
代码简洁度 需处理 if key in d 或用 .get() 代码更少,逻辑更直接
初始化 d = {} d = defaultdict(type)
性能 使用 .setdefault() 较慢 通常比使用 dict.setdefault() 更快
适用场景 只需要简单的键值存储,或需要严格检查键是否存在 计数、分组、构建嵌套数据结构

什么时候用哪个?

  • 如果你在做累加、聚合、分组操作,defaultdict 是更好的选择,代码更优雅且效率高。
  • 如果你只是查表,或者你不希望字典因为错误的查询而自动产生垃圾数据,请使用 普通 dict
00:00
00:00