Well, the question is in the title: how do I define a python dictionary with immutable keys but mutable values? I came up with this (in python 2.x):
class FixedDict(dict):
"""
A dictionary with a fixed set of keys
"""
def __init__(self, dictionary):
dict.__init__(self)
for key in dictionary.keys():
dict.__setitem__(self, key, dictionary[key])
def __setitem__(self, key, item):
if key not in self:
raise KeyError("The key '" +key+"' is not defined")
dict.__setitem__(self, key, item)
but it looks to me (unsurprisingly) rather sloppy. In particular, is this safe or is there the risk of actually changing/adding some keys, since I'm inheriting from dict? Thanks.
The problem with direct inheritance from
dict
is that it's quite hard to comply with the fulldict
's contract (e.g. in your case,update
method won't behave in a consistent way).What you want, is to extend the
collections.MutableMapping
:Note that the original (wrapped) dict will be modified, if you don't want that to happen, use
copy
ordeepcopy
.Consider proxying
dict
instead of subclassing it. That means that only the methods that you define will be allowed, instead of falling back todict
's implementations.Also, you should use string formatting instead of
+
to generate the error message, since otherwise it will crash for any value that's not a string.How you prevent someone from adding new keys depends entirely on why someone might try to add new keys. As the comments state, most dictionary methods that modify the keys don't go through
__setitem__
, so a.update()
call will add new keys just fine.If you only expect someone to use
d[new_key] = v
, then your__setitem__
is fine. If they might use other ways to add keys, then you have to put in more work. And of course, they can always use this to do it anyway:You can't make things truly immutable in Python, you can only stop particular changes.