objects as mutable dictionary keys

Steven Bethard steven.bethard at gmail.com
Mon Dec 27 18:54:16 EST 2004


Peter Maas wrote:
> Steven Bethard schrieb:
> 
>> If lists were hashable, new programmers to Python would almost 
>> certainly make mistakes like:
>>
>> py> d = {[1, 2, 3]: 'abc'}
> 
> 
>  > The coder here almost certainly *doesn't* want that list to be compared
>  > by id.  The only way to get a binding for that list would be using the
>  > dict's keys or __iter__ methods.
> 
> That's what I meant when I said that for lists id() doesn't make sense
> as hash because of the list literals.

As Andrew Koenig said, this has less to do with the fact that lists can 
be written with list literals, and more to do with the fact that lists 
are mutable containers.  Because they're containers, it makes sense to 
compare them by comparing their contents.  But because they're mutable, 
a hash value based on their contents cannot be guaranteed to be stable. 
  Hashing them by their id would force the user to mentally switch 
between thinking of lists as containers and thinking of lists as 
non-container objects.

Note that there is no such thing as a 'set literal', yet sets exhibit 
the same behavior:

py> d = {set([1, 2]):100, set('a b'.split()):200}
Traceback (most recent call last):
   File "<interactive input>", line 1, in ?
TypeError: set objects are unhashable

Sets are containers, and thus should be comparable by their contents. 
But sets are mutable, so they cannot be hashed by their contents. 
Rather than force the user to do the mental mind-switch between 
container and non-container, Python opts to make sets unhashable.

Note that, much as tuples are to lists, frozensets are to sets:

py> d = {frozenset([1, 2]):100, frozenset('a b'.split()):200}
py> d[frozenset([2, 1])]
100
py> d[frozenset(['b', 'a'])]
200

Because frozensets are immutable, they can not only be compared by their 
contents, but they can be hashed by these contents as well.

Steve



More information about the Python-list mailing list