不可变字典的可变包装

时间:2019-04-26 22:05:22

标签: python dictionary memory immutability python-3.7

这是问题所在;我有一本不可变的字典,里面有很多项目。该字典中包含的键类型和值类型本身是不可变的。我希望能够更改此字典(添加/删除/替换键值对),而不必完整复制字典。

我正在为遵循dict契约的不可变dict设想一些包装器类,对于未更新的值默认为不可变dict。我看到了How to “perfectly” override a dict?帖子,我打算利用它来制作此包装器。

在我开始实施该设计之前,我只想问-语言是否已经提供了这种结构?或者我还能如何达到预期的效果?我使用的是最新版本的Python(3.7),因此我可以使用所有可用的语言功能。谢谢!

2 个答案:

答案 0 :(得分:2)

看看collections.ChainMap。它是围绕多个词典的包装:所有写操作都进入第一个词典,并且按映射顺序搜索查找。所以我认为您可以执行以下操作:

modified_map = {}
mutable_map = collections.ChainMap(modified_map, huge_immutable_map)

答案 1 :(得分:0)

假设您使用了this one之类的frozendict实现:

class frozendict(collections.Mapping):
    """
    An immutable wrapper around dictionaries that implements the complete :py:class:`collections.Mapping`
    interface. It can be used as a drop-in replacement for dictionaries where immutability is desired.
    """

    dict_cls = dict

    def __init__(self, *args, **kwargs):
        self._dict = self.dict_cls(*args, **kwargs)
        self._hash = None

    def __getitem__(self, key):
        return self._dict[key]

    def __contains__(self, key):
        return key in self._dict

    def copy(self, **add_or_replace):
        return self.__class__(self, **add_or_replace)

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

    def __len__(self):
        return len(self._dict)

    def __repr__(self):
        return '<%s %r>' % (self.__class__.__name__, self._dict)

    def __hash__(self):
        if self._hash is None:
            h = 0
            for key, value in self._dict.items():
                h ^= hash((key, value))
            self._hash = h
        return self._hash

如果您想要对其进行变异,则可以进入并变异self._dict

d = frozendict({'a': 1, 'b': 2})
d['a'] = 3  # This fails
mutable_dict = d._dict
mutable_dict['a'] = 3  # This works
print(d['a'])

接触到班级受保护的成员有点麻烦,但是我想这没关系,因为您要尝试做的事情有点讨厌。如果要使用可变字典(仅dict),请使用一个。如果您不想改变它,请使用上述的frozendict实现。如此多变和一成不变的讽刺毫无意义。 frozendict所做的全部是,它没有实现突变dunder方法(__setitem____delitem__等)。在引擎盖下,frozendict由规则的可变dict表示。

在我看来,以上方法优于您所链接的方法。在许多情况下,可组合性(具有frozendict具有_dict属性)比继承(子类dict的继承)容易解释。