How to make a tuple including a numpy array hashable?

Demento picture Demento · Oct 26, 2017 · Viewed 6.9k times · Source

One way to make a numpy array hashable is setting it to read-only. This has worked for me in the past. But when I use such a numpy array in a tuple, the whole tuple is no longer hashable, which I do not understand. Here is the sample code I put together to illustrate the problem:

import numpy as np

npArray = np.ones((1,1))
npArray.flags.writeable = False
print(npArray.flags.writeable)

keySet = (0, npArray)
print(keySet[1].flags.writeable)

myDict = {keySet : 1}

First I create a simple numpy array and set it to read-only. Then I add it to a tuple and check if it is still read-only (which it is).

When I want to use the tuple as key in a dictionary, I get the error TypeError: unhashable type: 'numpy.ndarray'.

Here is the output of my sample code:

False
False
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    myDict = {keySet : 1}
TypeError: unhashable type: 'numpy.ndarray'

What can I do to make my tuple hashable and why does Python show this behavior in the first place?

Answer

user2357112 supports Monica picture user2357112 supports Monica · Oct 26, 2017

You claim that

One way to make a numpy array hashable is setting it to read-only

but that's not actually true. Setting an array to read-only just makes it read-only. It doesn't make the array hashable, for multiple reasons.

The first reason is that an array with the writeable flag set to False is still mutable. First, you can always set writeable=True again and resume writing to it, or do more exotic things like reassign its shape even while writeable is False. Second, even without touching the array itself, you could mutate its data through another view that has writeable=True.

>>> x = numpy.arange(5)
>>> y = x[:]
>>> x.flags.writeable = False
>>> x
array([0, 1, 2, 3, 4])
>>> y[0] = 5
>>> x
array([5, 1, 2, 3, 4])

Second, for hashability to be meaningful, objects must first be equatable - == must return a boolean, and must be an equivalence relation. NumPy arrays don't do that. The purpose of hash values is to quickly locate equal objects, but when your objects don't even have a built-in notion of equality, there's not much point to providing hashes.


You're not going to get hashable tuples with arrays inside. You're not even going to get hashable arrays. The closest you can get is to put some other representation of the array's data in the tuple.