python 将`defaultdict`公开为常规`dict`

sbtkgmzw  于 2023-04-28  发布在  Python
关注(0)|答案(3)|浏览(89)

我使用defaultdict(set)在一个非常大的数据结构中填充内部Map。填充完后,整个结构(包括Map)将公开给客户端代码。在这一点上,我不希望任何人修改Map。
没有人会故意的。但有时候,客户端代码可能会意外地引用到一个不存在的元素。此时,一个普通的字典会产生KeyError,但由于Map是defaultdict,它只是在那个键上创建一个新元素(一个空集)。这是很难捕捉的,因为一切都是悄悄发生的。但是我需要确保这种情况不会发生(语义实际上不会中断,但是Map会变得很大)。
我该怎么办?我可以看到这些选择:
1.在当前和将来的客户端代码中找到所有对Map执行字典查找的示例,并将其转换为mapping.get(k, {})。这太可怕了
1.在数据结构完全初始化后,通过将其转换为dict来“冻结”defaultdict。(我知道它并没有真正冻结,但我相信客户端代码实际上不会编写mapping[k] = v。)不雅,和一个大的性能击中。
1.将defaultdict Package 成dict接口。有什么优雅的方法吗?但是我担心性能会受到很大的影响(这种查找在紧密循环中使用得很频繁)。
1.子类defaultdict并添加一个方法,该方法“关闭”所有defaultdict功能,使其表现得像常规dict一样。它是上面3的变体,但我不确定它是否更快。如果不依赖于实现细节,我不知道它是否可行。
1.在数据结构中使用常规的dict,重写所有代码,首先检查元素是否在字典中,如果不在,则添加它。不太好

kzmpq1sx

kzmpq1sx1#

defaultdict文档对default_factory说:
如果default_factory属性为None,则会引发KeyError异常,并将key作为参数。
如果你只是将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'
>>>

不知道这是否是最好的方法,但似乎有效。

qvtsj1bj

qvtsj1bj2#

一旦你完成了你的defaultdict的填充,你可以简单地从它创建一个普通的dict:

my_dict = dict(my_default_dict)

如果默认dict是递归默认dict,请参阅this answer,它具有递归解决方案。

rmbxnbpk

rmbxnbpk3#

你可以创建一个类,它包含对你的dict的引用,并防止setitem()

from collections import Mapping

class MyDict(Mapping):
    def __init__(self, d):
        self.d = d;

    def __getitem__(self, k):
        return self.d[k]

    def __iter__(self):
        return self.__iter__()

    def __setitem__(self, k, v):
        if k not in self.d.keys():
            raise KeyError
        else:
            self.d[k] = v

相关问题