如何在Python中使字典只读

时间:2013-09-26 08:18:20

标签: python dictionary

我有一个类:

class A:
    def __init__(self):
        self.data = {}

在某些时刻我想禁止self.data字段修改。

我在PEP-416 rejection notice读到有很多方法可以做到这一点。所以我想找到它们是什么。

我试过了:

a = A()
a.data = types.MappingProxyType(a.data)

这应该可以,但首先,它的python3.3 +和第二,当我这样做“禁止”多次我得到这个:

>>> a.data = types.MappingProxyType(a.data)
>>> a.data = types.MappingProxyType(a.data)
>>> a.data
mappingproxy(mappingproxy({}))

尽管获得mappingproxy({})会好得多,因为我要“禁止”很多次。检查isinstance(MappingProxyType)是一种选择,但我认为可以存在其他选项。

由于

5 个答案:

答案 0 :(得分:29)

使用collections.Mapping例如

import collections

class DictWrapper(collections.Mapping):

    def __init__(self, data):
        self._data = data

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

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

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

HTH,

答案 1 :(得分:22)

这是快速(浅)只读字典的完整实现:​​

class ReadOnlyDict(dict):
    def __readonly__(self, *args, **kwargs):
        raise RuntimeError("Cannot modify ReadOnlyDict")
    __setitem__ = __readonly__
    __delitem__ = __readonly__
    pop = __readonly__
    popitem = __readonly__
    clear = __readonly__
    update = __readonly__
    setdefault = __readonly__
    del __readonly__

答案 2 :(得分:6)

很简单,你只需覆盖默认的dict方法!
这是一个例子:

class ReadOnlyDict(dict):

    __readonly = False

    def readonly(self, allow=1):
        """Allow or deny modifying dictionary"""
        self.__readonly = bool(allow)

    def __setitem__(self, key, value):

        if self.__readonly:
            raise TypeError, "__setitem__ is not supported"
        return dict.__setitem__(self, key, value)

    def __delitem__(self, key):

        if self.__readonly:
            raise TypeError, "__delitem__ is not supported"
        return dict.__delitem__(self, key)

顺便说一句,您还可以删除.pop.update以及其他所需的方法。只是玩弄它。

答案 3 :(得分:0)

怎么样?这是@mouad答案的更新。

import json
from collections import OrderedDict
from collections.abc import Mapping


class ReadOnlyJsonObject(Mapping):
    def __init__(self, data, dumps_kw: dict=None, loads_kw: dict=None):
        if dumps_kw is None:
            dumps_kw = dict()
        if loads_kw is None:
            self._loads_kw = dict(object_pairs_hook=OrderedDict)
        else:
            self._loads_kw = loads_kw

        if isinstance(data, str):
            self._json_string = data
        else:
            self._json_string = json.dumps(data, **dumps_kw)

    @property
    def _data(self):
        return json.loads(self._json_string, **self._loads_kw)

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

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

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

    def __str__(self):
        return self._json_string

但是不确定性能。我在一个真实的项目https://github.com/patarapolw/AnkiTools/blob/master/AnkiTools/tools/defaults.py

中使用了它

答案 4 :(得分:0)

最好的方法是像这样从UserDict派生

from collections import UserDict

class MyReadOnlyDict(UserDict):
   def my_set(self, key, val, more_params):
       # do something special
       # custom logic etc
       self.data[key] = val

   def __setitem__(self, key, val):
       raise NotImplementedError('This dictionary cannot me updated')

   def __delitem__(self, key):
       raise NotImplementedError('This dictionary does not allow delete')

此方法的优点是您仍然可以在类中使用通过访问self.data来更新字典的内部方法。