簡體   English   中英

如何使字典只讀?

[英]How to make dictionary read-only?

我有一個像這樣的課程:

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

並且在某些時候我想禁止self.data字段修改。

我在PEP-416 拒絕通知中讀到有很多方法可以做到這一點。 所以我想找出它們是什么。

我試過這個:

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)是一個選項,但我認為可以存在其他選項。

謝謝

使用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)

這是快速(淺)只讀字典的完整實現:

def _readonly(self, *args, **kwargs):
    raise RuntimeError("Cannot modify ReadOnlyDict")

class ReadOnlyDict(dict):
    __setitem__ = _readonly
    __delitem__ = _readonly
    pop = _readonly
    popitem = _readonly
    clear = _readonly
    update = _readonly
    setdefault = _readonly

我之前的(更糟糕的)實現如下(感謝@mtraceur 的精彩評論!):

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__

很簡單,你只需覆蓋默認 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和其他您需要的方法。 只是玩弄它。

最好的方法是像這樣從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 be updated')

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

這種方法的優點是您仍然可以在您的類中擁有可以通過訪問self.data來更新字典的內部方法。

怎么樣? 這是@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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM