定义具有不可变键但值可变的python字典

定义具有不可变键但值可变的python字典,python,dictionary,key,immutability,Python,Dictionary,Key,Immutability,那么,问题就在标题中:如何定义一个键不可变但值可变的python字典?我提出了这个(在Python2.x中): 但在我看来(毫不奇怪)它相当草率。特别是,这是安全的还是有实际更改/添加一些密钥的风险,因为我是从dict继承的? 谢谢。考虑代理dict而不是子类化它。这意味着只允许您定义的方法,而不是退回到dict的实现 class FixedDict(object): def __init__(self, dictionary): self._dictio

那么,问题就在标题中:如何定义一个键不可变但值可变的python字典?我提出了这个(在Python2.x中):

但在我看来(毫不奇怪)它相当草率。特别是,这是安全的还是有实际更改/添加一些密钥的风险,因为我是从dict继承的?
谢谢。

考虑代理
dict
而不是子类化它。这意味着只允许您定义的方法,而不是退回到dict的实现

class FixedDict(object):
        def __init__(self, dictionary):
            self._dictionary = dictionary
        def __setitem__(self, key, item):
                if key not in self._dictionary:
                    raise KeyError("The key {} is not defined.".format(key))
                self._dictionary[key] = item
        def __getitem__(self, key):
            return self._dictionary[key]

此外,您应该使用字符串格式而不是
+
来生成错误消息,因为否则,任何非字符串的值都会崩溃。

如何阻止某人添加新键完全取决于某人尝试添加新键的原因。正如注释所述,大多数修改键的字典方法都不会经过
\uuuu setitem\uuuu
,因此
.update()
调用可以添加新键

如果您只希望有人使用
d[new_key]=v
,那么您的
\uuuu setitem\uuuu
就可以了。如果他们可能使用其他方式添加密钥,那么您必须投入更多的工作。当然,他们也可以用这个来做:

dict.__setitem__(d, new_key, v)

在Python中,您不能使事情真正不变,只能停止特定的更改。

直接继承dict的问题是很难遵守完整的dict契约(例如,在您的情况下,
update
方法的行为不一致)

您想要的是扩展:


请注意,原始(包装的)dict将被修改,如果您不希望发生这种情况,请使用。

好吧,可能有人会在
FixedDict
的实例上调用
dict.\uuuuu setitem\uuuuuuuuuuuuuuuuuuuuuu()
,不是吗?您应该检查以确保
dict.update
调用
\uuuuuu setitem\uuuuuuuuuuuuuuuuuuuuuuu
——尽管如此,我不确定这是否依赖于实现…(
update
绕过
\uuuu setitem\uuuu
)所有C内置函数的实现都会绕过python的方法,以避免子类破坏它们。“避免子类破坏它们”?正是旁路使得子类破坏了它们。它们绕过
\uuuuuuuuuuuuuuuuuuu设置项
以获得速度。
dict.__setitem__(d, new_key, v)
import collections

class FixedDict(collections.MutableMapping):
    def __init__(self, data):
        self.__data = data

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

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

    def __setitem__(self, k, v):
        if k not in self.__data:
            raise KeyError(k)

        self.__data[k] = v

    def __delitem__(self, k):
        raise NotImplementedError

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

    def __contains__(self, k):
        return k in self.__data