问题
I have a class like:
class A:
def __init__(self):
self.data = {}
and at some moment I want to prohibit self.data
fields modification.
I've read in PEP-416 rejection notice that there are a lot of ways to do it. So I'd like to find what they are.
I tried this:
a = A()
a.data = types.MappingProxyType(a.data)
That should work but first, its python3.3+ and second, when I do this "prohibition" multiple times I get this:
>>> a.data = types.MappingProxyType(a.data)
>>> a.data = types.MappingProxyType(a.data)
>>> a.data
mappingproxy(mappingproxy({}))
though it would be much better to get just mappingproxy({})
as I am going to "prohibit" a lot of times. Check of isinstance(MappingProxyType)
is an option, but I think that other options can exist.
Thanks
回答1:
Use collections.Mapping e.g.
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)
回答2:
This is full implementation of fast (shallow-)read-only dict:
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__
回答3:
Very easy, you just override default dict's methods!
Here is an example:
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)
BTW, you can also remove .pop
, .update
and other methods you need. Just play around with it.
回答4:
The best way is to derive from UserDict
like this:
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')
The advantage of this method is that you can still have internal methods in your class that can update dictionary by accessing self.data
.
回答5:
How about? It is the update of @mouad 's answer.
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
Not sure about the performance, though. I use this one in a real project https://github.com/patarapolw/AnkiTools/blob/master/AnkiTools/tools/defaults.py
来源:https://stackoverflow.com/questions/19022868/how-to-make-dictionary-read-only-in-python