Skip to content Skip to sidebar Skip to footer

Immutable Dictionary, Only Use As A Key For Another Dictionary

I had the need to implement a hashable dict so I could use a dictionary as a key for another dictionary. A few months ago I used this implementation: Python hashable dicts However

Solution 1:

If you are only using it as a key for another dict, you could go for frozenset(mutabledict.items()). If you need to access the underlying mappings, you could then use that as the parameter to dict.

mutabledict = dict(zip('abc', range(3)))
immutable = frozenset(mutabledict.items())
read_frozen = dict(immutable)
read_frozen['a'] # => 1

Note that you could also combine this with a class derived from dict, and use the frozenset as the source of the hash, while disabling __setitem__, as suggested in another answer. (@RaymondHettinger's answer for code which does just that).

Solution 2:

The Mapping abstract base class makes this easy to implement:

import collections

classImmutableDict(collections.Mapping):
    def__init__(self, somedict):
        self._dict = dict(somedict)   # make a copy
        self._hash = Nonedef__getitem__(self, key):
        return self._dict[key]

    def__len__(self):
        returnlen(self._dict)

    def__iter__(self):
        returniter(self._dict)

    def__hash__(self):
        if self._hashisNone:
            self._hash = hash(frozenset(self._dict.items()))
        return self._hashdef__eq__(self, other):
        return self._dict == other._dict

Solution 3:

I realize this has already been answered, but types.MappingProxyType is an analogous implementation for Python 3.3. Regarding the original question of safety, there is a discussion in PEP 416 -- Add a frozendict builtin type on why the idea of a frozendict was rejected.

Solution 4:

In order for your immutable dictionary to be safe, all it needs to do is never change its hash. Why don't you just disable __setitem__ as follows:

classImmutableDict(dict):
    def__setitem__(self, key, value):
        raise Exception("Can't touch this")
    def__hash__(self):
        returnhash(tuple(sorted(self.items())))

a = ImmutableDict({'a':1})
b = {a:1}
print b
print b[a]
a['a'] = 0

The output of the script is:

{{'a': 1}: 1}
1Traceback (most recent call last):
  File "ex.py", line 11, in <module>
    a['a'] = 0
  File "ex.py", line 3, in __setitem__
    raise Exception("Can't touch this")
Exception: Can't touch this

Solution 5:

Here is a link to pip install-able implementation of @RaymondHettinger's answer: https://github.com/pcattori/icicle

Simply pip install icicle and you can from icicle import FrozenDict!

Update:icicle has been deprecated in favor of maps: https://github.com/pcattori/maps (documentation, PyPI).

Post a Comment for "Immutable Dictionary, Only Use As A Key For Another Dictionary"