from collections.abc import Mapping class ValueImmutableDict(Mapping): _EMPTY_VALUE = object() def __init__(self, somedict): self._dict = dict(somedict) # make a copy self._hash = None def __setitem__(self, key, value): cur_value = self._dict.get(key, self._EMPTY_VALUE) if cur_value is not self._EMPTY_VALUE and cur_value != value: raise KeyError(f"can't change value of key: k={key},v={cur_value},new_v={value}") self._dict[key] = value def __getitem__(self, key): return self._dict[key] def __len__(self): return len(self._dict) def __iter__(self): return iter(self._dict) def __hash__(self): if self._hash is None: self._hash = hash(frozenset(self._dict.items())) return self._hash def __eq__(self, other): return self._dict == other._dict