Python:创建后冻结字典键[重复]

Posted

技术标签:

【中文标题】Python:创建后冻结字典键[重复]【英文标题】:Python: Freeze dict keys after creation [duplicate] 【发布时间】:2014-10-04 13:25:11 【问题描述】:

是否可以在创建后“冻结”python dict,从而无法向其中添加新键?只能更改现有的键值。

如果不是,您如何知道何时更改现有键值对以及何时添加新键值对?

【问题讨论】:

您可以使用if(key in dict):...检查字典中是否有值 所以您只想冻结键,而不是所有字典,对吧? @jonrsharpe -- 我不确定我是否同意这个结束。 OP 说“冻结”,但并不是真正的意思,因为他/她真的只是想指定可以操作的键而不允许任何其他键。 . . 相关:***.com/questions/2703599/what-would-be-a-frozen-dict 我不认为这是一个完全相同的副本,因为您只想冻结键。顺便说一句,在标准库中没有这样的东西。为了知道某个键是否在字典中,请使用@iwin 建议:print 'already in' if key in dict else 'not here' 【参考方案1】:

可能是这样的:

class FreezableDict (dict):
    __frozen = False

    def freeze (self):
        self.__frozen = True

    def __setitem__ (self, key, value):
        if self.__frozen and key not in self:
            raise ValueError('Dictionary is frozen')
        super().__setitem__(key, value)
>>> x = FreezableDict('foo': 'bar', 'baz': 'bla')
>>> x
'baz': 'bla', 'foo': 'bar'
>>> x['asdf'] = 'fdsa'
>>> x
'asdf': 'fdsa', 'baz': 'bla', 'foo': 'bar'
>>> x.freeze()
>>> x['hello'] = 'world'
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    x['hello'] = 'world'
  File "<pyshell#13>", line 8, in __setitem__
    raise ValueError('Dictionary is frozen')
ValueError: Dictionary is frozen

请注意,您可能还想覆盖其他方法,包括 __delitem__updatesetdefaultpoppopitem,因为它们都可以修改字典。


如果您有兴趣完全锁定字典,您可以使用types.MappingProxyType,它为您的字典提供只读视图。一旦你创建了你的普通字典,你就可以创建一个它的映射代理,它根本没有任何分配/更新功能。然后,您还可以删除对原始字典的任何引用(映射将保留一个),以防止它被用于进一步更新它:

>>> x = 'foo': 'bar'
>>> y = types.MappingProxyType(x)
>>> y
mappingproxy('foo': 'bar')
>>> x['baz'] = 'bla'
>>> y
mappingproxy('baz': 'bla', 'foo': 'bar')
>>> y['hello'] = 'world'
Traceback (most recent call last):
  File "<pyshell#55>", line 1, in <module>
    y['hello'] = 'world'
TypeError: 'mappingproxy' object does not support item assignment
>>> del x
>>> y
mappingproxy('baz': 'bla', 'foo': 'bar')

或者只是在一行中,没有对原始字典的引用:

>>> x = types.MappingProxyType('foo': 'bar', 'baz': 'bla')
>>> x
mappingproxy('baz': 'bla', 'foo': 'bar')
>>> x['hello'] = 'world'
Traceback (most recent call last):
  File "<pyshell#60>", line 1, in <module>
    x['hello'] = 'world'
TypeError: 'mappingproxy' object does not support item assignment

【讨论】:

好主意,但我不喜欢类名FrozenDict,这对我来说暗示了一个不可变的、可散列的字典。 @wim 我愿意接受建议;) +1 但可能会赢得胜利class FreezableDict 喜欢使用types.MappingProxyType - 绝对是+1 是否有与 2.7 等效的 MappingProxyType ?【参考方案2】:

这对于“香草”字典是不可能的。您可能想要继承 collections.MutableMapping 。 . .

后面是未经测试的代码

class FrozenKeyDict(collections.MutableMapping):
    """Mapping which doesn't allow keys to be added/deleted.

    It does allow existing key/value pairs to be modified.
    """
    def __init__(self, *args, **kwargs):
        self._frozen = False
        self._dict = 
        super(FrozenKeyDict, self).__init__(*args, **kwargs)
        self._frozen = True

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

    def __setitem__(self, key, value):
        if self._frozen and key not in self._dict:
            raise KeyError('must be one of %s' % list(self))
        self._dict[key] = value

    def __delitem__(self, key):
        # modify to suit your needs ...
        raise KeyError('Removing keys not supported')

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

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

【讨论】:

你的super 和类名似乎不一致:) @JonClements -- 天哪!当您无法决定如何命名事物并且不使用 python3.x 作为示例时,就会发生这种情况;-) 我也可能将 self._dict.keys() 更改为 list(self._dict) 所以它也兼容 3.x @JonClements -- 我来回讨论那个 -- 人们经常期望list(self._dict) 列出items,而不仅仅是键。也许list(self) 强行一点思考? 嗯,list(self) 将是空的,因为所有数据都在 self._dict 而不是对象的 collections.MutableMapping 部分(选择一个或另一个)

以上是关于Python:创建后冻结字典键[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python基础编程——字典的创建

如何从 CSV 创建字典,其中两列作为 Python 中的键 [重复]

python列表,元组,字典,集合的比较总结

好好学python · 字典

Python:字典

如何为内部字典键创建新列表或设置对象,以便不重复更新同一对象?