Hashables

Published

2023-07-31

Hashables

The keys of a dictionary cannot be arbitrary Python objects. In order to serve as a key, an object must be hashable.

Without delving into too much technical detail, the reason is fairly straightforward. We can’t have keys that might change!

Imagine if that dictionary or thesaurus on your desk had magical keys that could change. You’d never be able to find anything. Accordingly, all keys in a dictionary must be hashable—and not subject to possible change.

Hashing is a process whereby we calculate a number (called a hash) from an object. In order to serve as a dictionary key, this hash value must never change.

What kinds of objects are hashable? Actually most of the objects we’ve seen so far are hashable.

Anything that is immutable and is not a container is hashable. This includes int, float, bool, str. It even includes objects of type range (though it would be very peculiar indeed if someone were to use a range as a dictionary key).

What about things that are immutable and are containers? Here we’re speaking of tuples. If all the elements of a tuple are themselves immutable, then the tuple is hashable. If a tuple contains a mutable object, say, a list, then it is not hashable.

We can inspect the hash values of various objects using the built-in function, hash().

>>> x = 2
>>> hash(x)
2
>>> x = 4.11
>>> hash(x)
253642731013507076
>>> x = 'hello'
>>> hash(x)
1222179648610370860
>>> x = True
>>> hash(x)
1
>>> x = (1, 2, 3)
>>> hash(x)
529344067295497451

Now, what happens if we try this on something unhashable?

>>> x = [1, 2, 3]
>>> hash(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

What happens if we try an immutable container (tuple) which contains a mutable object (list)?

>>> x = (1, 2, [3])
>>> hash(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Now, a tuple can contain a tuple, which may contain another tuple and so on. All it takes is one mutable element, no matter how deeply nested, to make an object unhashable.

>>> x = (1, 2, (3, 4, (5, 6, (7, 8, [9]))))
>>> hash(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Finally, it should go without saying that since dictionaries are mutable, they are not hashable, and thus a dictionary cannot serve as a key for another dictionary.

>>> x = {'foo': 'bar'}
>>> hash(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).