In the code below I create a class ImmutableDict that appears to have a __setitem__ implementation that should throw an exception, but it doesn't. Why not?
from typing import Mapping, TypeVar
KT = TypeVar('KT')
VT_co = TypeVar('VT_co', covariant=True)
class Immutable:
def __init__(self, *args, **kwargs):
super(Immutable, self).__init__(*args, **kwargs)
# set them all to self.raise_immutable
self.__setitem__ = self.__delitem__ = self.setdefault = self.update = self.pop = self.popitem = self.clear = self.raise_immutable
def raise_immutable(self, *args, **kwargs):
clsname = self.__class__.__name__
raise TypeError(f"{clsname} objects are immutable")
def __repr__(self):
clsname = self.__class__.__name__
content = super(Immutable, self).__repr__()
return f"{clsname}({content}"
class ImmutableDict(Immutable, dict, Mapping[KT, VT_co]):
def __hash__(self):
return hash(tuple(self.items()))
i = ImmutableDict({'a':1})
print(i) # ImmutableDict({'a': 1})
print(i.__setitem__) # <bound method Immutable.raise_immutable of ImmutableDict({'a': 1})>
# i.__setitem__('b', 2) # this throws an exception as desired
i['b'] = 2 # but yet this works?
print(i) # ImmutableDict({'a': 1, 'b': 2})