views:

567

answers:

3

I mean why cant we put key of dict as dict?

that means we can't have dictionary having key as another dictionary...

+11  A: 

Short answer: because they are mutable containers.

If a dict was hashed, its hash would change as you changed its contents.

Ben James
I don't even want to begin to imagine the nightmarish logic it would take to use an object as the key.
David
Actually Python makes hashing objects easy, it gives each one a unique and constant identity which can be hashed.
Ben James
yes, but by default instances of user defined objects always compare unequal.
hop
but I wonder what's the reason behind it - to keem dict. unhashable?
Tumbleweed
make a hashable representation of the dict if you must -- for example `frozenset(D.items())` (for `D` dict). A `frozenset` is a hashable and immutable set -- a `set` is unhashable for the same reason as `dict`.
kaizer.se
@shahjapan: the reason is that it prevents hard-to-find bugs, especially for people that don't understand hashing all that well. As Dave Kirby shows below, there is a simple workaround, but that you have to use a workaround is a simple warning that you need to understand what you are doing, lest you 'lose' key-value pairs.
Confusion
@Confusion yes thanks I understood now, but I was Wondering because if you consider java or c# Hashtables are hashable by default :-)
Tumbleweed
@kaizer.se: for frozenset to freeze a dictionary, all the dictionary keys and values need to be hashable too. try `frozenset({1:2, 3:[]})`.
ΤΖΩΤΖΙΟΥ
+1  A: 

None of the mutable container types in Python are hashable, because they are mutable and thus their hash value can change over their lifetime.

hop
tuples and strings are containers, yet hashable and immutable.
Ignacio Vazquez-Abrams
a stupid typo that you could easily have corrected
hop
@Ignacio Vazquez-Abrams: strings are sequences but not containers. Also, a tuple containing a non-hashable item is also non-hashable; try using `([1], {2:3})` as a dict key.
ΤΖΩΤΖΙΟΥ
+2  A: 

As others have said, the hash value of a dict changes as the contents change.

However if you really need to use dicts as keys, you can subclass dict to make a hashable version.

>>> class hashabledict(dict):
...    def __hash__(self):
...        return id(self)
... 
>>> hd = hashabledict()
>>> d = dict()
>>> d[hd] = "foo"
>>> d
{{}: 'foo'}

>>> hd["hello"] = "world"
>>> d
{{'hello': 'world'}: 'foo'}

This replaces the hash value used for the dict with the object's address in memory.

Dave Kirby
and then can I replace normal dict byedict = hashabledict
Tumbleweed
But this is useless: if I store a value under `{}`, I can't look it up with `{}`, because the two empty hashabledicts have different ids, and different hashes. The important thing about a hash function is that it must return the same hash for two "equal" values.
Ned Batchelder
@Ned - Doh! You are right. What is really needed is a frozendict that acts the same way as a frozenset. You could subclass dict to define one, as in this recipe on ASPN: http://code.activestate.com/recipes/414283/
Dave Kirby