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