将`defaultdict`暴露为常规`dict`

max*_*max 25 python wrapper python-3.x defaultdict

defaultdict(set)用来填充非常大的数据结构中的内部映射.填充后,整个结构(包括映射)将暴露给客户端代码.那时,我不希望任何人修改映射.

并且没有人故意这样做.但有时,客户端代码可能会意外地引用不存在的元素.此时,普通字典会引发KeyError,但由于映射是defaultdict,它只是在该键上创建一个新元素(空集).这很难理解,因为一切都是默默无闻的.但我需要确保不会发生这种情况(语义实际上不会中断,但映射会变得很大).

我该怎么办?我可以看到这些选择:

  1. 查找当前和未来客户端代码中的所有实例,其中对映射执行字典查找,并将其转换为其他实例mapping.get(k, {}).这太可怕了.

  2. defaultdict数据结构完全初始化后,通过将其转换为"冻结" dict.(我知道它并没有真正冻结,但我相信客户端代码实际上并没有写mapping[k] = v.)不雅,并且性能大.

  3. 包装defaultdict成一个dict界面.这样做的优雅方式是什么?我担心性能损失可能很大(这种查找在紧密循环中被大量使用).

  4. 子类defaultdict并添加一个"关闭"所有defaultdict功能的方法,使其表现得像是常规的dict.这是上面3的变种,但我不确定它是否更快.如果不依赖于实施细节,我不知道它是否可行.

  5. dict在数据结构中使用regular ,重写那里的所有代码,首先检查元素是否在字典中,如果不在,则添加它.不好.

Nea*_*eal 39

defaultdictdocs说default_factory:

如果default_factory属性为None,则会以key作为参数引发KeyError异常.

如果你只是将defaultdict的default_factory设置为None?例如,

>>> d = defaultdict(int)
>>> d['a'] += 1
>>> d
defaultdict(<type 'int'>, {'a': 1})
>>> d.default_factory = None
>>> d['b'] += 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'
>>> 
Run Code Online (Sandbox Code Playgroud)

不确定这是否是最佳方法,但似乎有效.

  • @max - 文档明确指出`default_factory`是一个**可写的**属性,所以它应该是安全的. (3认同)
  • 谁知道我提出的解决方案已经作为`defaultdict` 的一个特性实现了?很棒的发现。(+1) (2认同)