使用不可变键但可变值定义python字典

Define a python dictionary with immutable keys but mutable values

好吧,问题在标题中:我如何定义一个具有不变键但可变值的python字典?我想到了这个(在python 2.x中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FixedDict(dict):
   """
    A dictionary with a fixed set of keys
   """


    def __init__(self, dictionary):
        dict.__init__(self)
        for key in dictionary.keys():
            dict.__setitem__(self, key, dictionary[key])

    def __setitem__(self, key, item):
        if key not in self:
            raise KeyError("The key '" +key+"' is not defined")
        dict.__setitem__(self, key, item)

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


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

你想要的是扩展collections.MutableMapping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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

请注意,将修改原始(包装)dict,如果您不希望这样做,请使用copydeepcopy


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

1
2
3
4
5
6
7
8
9
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]

另外,您应该使用字符串格式而不是+来生成错误消息,否则它将对任何不是字符串的值崩溃。


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

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

1
dict.__setitem__(d, new_key, v)

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