简体   繁体   English

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

[英]Define a python dictionary with immutable keys but mutable values

Well, the question is in the title: how do I define a python dictionary with immutable keys but mutable values? 好吧,问题在于标题:如何定义具有不可变键但可变值的python字典? I came up with this (in python 2.x): 我想出了这个(在python 2.x中):

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)

but it looks to me (unsurprisingly) rather sloppy. 但它看起来(不出所料)相当草率。 In particular, is this safe or is there the risk of actually changing/adding some keys, since I'm inheriting from dict? 特别是,这是安全还是存在实际更改/添加某些密钥的风险,因为我是从dict继承的? Thanks. 谢谢。

The problem with direct inheritance from dict is that it's quite hard to comply with the full dict 's contract (eg in your case, update method won't behave in a consistent way). 直接继承来自dict的问题是很难遵守完整的dict的契约(例如在你的情况下, update方法不会以一致的方式运行)。

What you want, is to extend the collections.MutableMapping : 你想要的是扩展collections.MutableMapping

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

Note that the original (wrapped) dict will be modified, if you don't want that to happen, use copy or deepcopy . 请注意,原始(包装)字典将被修改,如果您不希望发生这种情况,请使用copydeepcopy copy

Consider proxying dict instead of subclassing it. 考虑代理dict而不是子类化它。 That means that only the methods that you define will be allowed, instead of falling back to dict 's implementations. 这意味着只允许您定义的方法,而不是回退到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]

Also, you should use string formatting instead of + to generate the error message, since otherwise it will crash for any value that's not a string. 此外,您应该使用字符串格式而不是+来生成错误消息,否则它将为任何不是字符串的值崩溃。

How you prevent someone from adding new keys depends entirely on why someone might try to add new keys. 如何阻止某人添加新密钥完全取决于某人可能尝试添加新密钥的原因。 As the comments state, most dictionary methods that modify the keys don't go through __setitem__ , so a .update() call will add new keys just fine. 正如注释所述,修改键的大多数字典方法都没有经过__setitem__ ,因此.update()调用会添加新键。

If you only expect someone to use d[new_key] = v , then your __setitem__ is fine. 如果你只想要有人使用d[new_key] = v ,那么__setitem__就可以了。 If they might use other ways to add keys, then you have to put in more work. 如果他们可能使用其他方式添加密钥,那么您必须投入更多工作。 And of course, they can always use this to do it anyway: 当然,无论如何,他们总是可以用它来做到这一点:

dict.__setitem__(d, new_key, v)

You can't make things truly immutable in Python, you can only stop particular changes. 你不能在Python中使事物真正不可变,你只能停止特定的变化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM