Reputation: 41
I have a dictionary filled with key-object pairs. I want to make the dictionary immutable and I thought the best/easiest way is to cast it to a frozenset but frozenset(dict)
and also tuple(dict)
only stores the keys.
Using frozenset(dict.items())
I seem to get a frozenset with the key-object pairs but I don't know how to retrieve the values/keys.
I have the following code which works, as long as "__obfuscators" is a dictionary
def obfuscate_value(self, key, value):
obfuscator = self.__obfuscators.get(key)
if obfuscator is not None:
return obfuscator.obfuscate_value(value)
else:
return value
I tried this in an attempt to get it working with the frozen set:
def obfuscate_value(self, key, value):
try:
obfuscator = self.__obfuscators[key]
except:
return value
return obfuscator.obfuscate_value(value)
but this gives that frozenset does not have \__getitem__
and self.__obfuscators.__getattribute__(key)
always says it does not have the attribute (because I assume this searches for a function named key)
Is there a better way to make the dictionary immutable or how can I retrieve the object depending on the key?
Edit:
I ended up casting the dict to a tuple using tuple(obfuscator.items())
and then wrote my own find value function:
def find_obfuscator(self, key):
for item in self.__obfuscators:
x, y = item
if self.case_insensitive:
if x.lower() == key.lower():
return y
else:
if x == key:
return y
I would like to thank everyone for their efforts and input.
Upvotes: 4
Views: 5120
Reputation: 2381
You need a dict
that is capable of freezing? You can simply make one:
class FrozenDict(dict):
def __init__(self, *args, **kwargs):
self._frozen = False
dict.__init__(self, *args, **kwargs)
def freeze(self):
self._frozen = True
def __setitem__(self, key, value):
if (self._frozen):
raise TypeError("Attempted assignment to a frozen dict")
else:
return dict.__setitem__(self, key, value)
a = FrozenDict({7:8})
a[5] = 6
print(a)
a.freeze()
a[3] = 2 # raises TypeError
It will behave exactly like usual dict
until you call .freeze()
. Then it's frozen.
Upvotes: 0
Reputation: 8464
You can create an immutable view of a dictionary using types.MappingProxyType
:
from types import MappingProxyType
d = { 'a': 1 }
fd = MappingProxyType(d)
fd['a']
#output:
1
fd['a'] = 2
#output:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment
notice that you can still change the vaule object, so:
d = { 'a': [1] }
fd = MappingProxyType(d)
fd['a'].append(2)
fd['a']
#output:
[1,2]
will work.
Upvotes: 3
Reputation: 26956
Since you mention tuple(dict)
in your original post, probably the simplest solution to achieve what you want might simply be:
tuple(dict.items())
Upvotes: 0
Reputation: 37203
The simplest way I could think of to achieve what you want was to subclass the standard dict
type and overwrite its __setitem__
method:
class MyDict(dict):
def __setitem__(self, key, value):
raise NotImplementedError("This is a frozen dictionary")
This allows you to create dictionaries that cannot thereafter be changed by item assignment:
d = MyDict({1: 2, 3: 4})
or, equivalently:
d = MyDict([(1, 2), (3, 4)])
The dict then prints out just like a standard dict:
{1: 2, 3: 4}
But when you try to change a value (or add a new one):
d[1] = 15
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-21-a22420992053> in <module>()
----> 1 d[1] = 34
<ipython-input-18-03f266502231> in __setitem__(self, key, value)
1 class MyDict(dict):
2 def __setitem__(self, key, value):
----> 3 raise NotImplementedError("This is a frozen dictionary")
NotImplementedError: This is a frozen dictionary
Note that this isn't fully immutable, however:
d.update({1:17})
for example, will update it, but this solution might be good enough - it depends on the broader requirements.
Upvotes: 1
Reputation: 26
You could make a wrapper class that takes a dictionary and has a get item function but no set item. You'd need to add a few things for thread safety and hashing maybe but the basic class wouldn't be too difficult.
Upvotes: 0