Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable Dictionary with key-object pairs Python

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.

like image 322
ThunderM Avatar asked Oct 28 '25 10:10

ThunderM


2 Answers

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.

like image 142
Ohad Eytan Avatar answered Oct 31 '25 01:10

Ohad Eytan


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.

like image 41
holdenweb Avatar answered Oct 31 '25 00:10

holdenweb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!