如何以Pythonic方式正确重实现defaultdict?
正确实现Python defaultdict的方式
你之前的实现都漏了最关键的一步——把工厂函数生成的值插入字典,这正是collections.defaultdict的核心特性:用[]访问不存在的键时,不仅返回默认值,还会把这个值存进字典里。
正确的实现代码
from collections.abc import Callable class DefaultDict(dict): def __init__(self, factory: Callable[[], any]): self.factory = factory super().__init__() def __missing__(self, key): value = self.factory() self[key] = value # 核心:将生成的默认值存入字典 return value
为什么这个实现能符合预期?
- 当你用
x['b']访问不存在的键时,Python会自动调用__missing__方法:生成默认值,把值绑定到该键存入字典,再返回值。这时候再调用x.get('b'),就能获取到已经存入的默认值,和官方defaultdict行为完全一致。 - 不需要重写
get、pop等方法:这些方法本身不会触发__missing__,它们的行为和普通dict保持一致——比如get在键不存在时返回None(或你指定的默认值),pop在无默认值时抛出KeyError,这完全符合官方defaultdict的设计。
验证测试用例
运行你给出的测试代码,现在所有断言都会返回True:
import collections x = DefaultDict(lambda: 'no value :(') y = collections.defaultdict(lambda: 'no value :(') x['a'] = 'hello' y['a'] = 'hello' print(x['a'] == y['a']) # True print(x.get('a') == y.get('a')) # True print(x['b'] == y['b']) # True print(x.get('b') == y.get('b')) # True
关于CPython实现的疑问
CPython的defaultdict确实只实现了__missing__逻辑,因为dict的内置[]访问逻辑会在键不存在时自动检查并调用该方法,其他方法(如get)本身不依赖__missing__,所以不需要额外重写——这也是最符合Python风格的实现方式:利用现有父类的行为,只补充差异逻辑。
内容的提问来源于stack exchange,提问作者ollien
相关产品推荐
相关产品推荐

