This works
range(50)[np.asarray(10)]
This works
{}.get(50)
This doesn't because of unhashable type: 'numpy.ndarray'
{}.get(np.asarray(50))
Is there a reason why __hash__
isn't implemented for this case?
This works
range(50)[np.asarray(10)]
This works
{}.get(50)
This doesn't because of unhashable type: 'numpy.ndarray'
{}.get(np.asarray(50))
Is there a reason why __hash__
isn't implemented for this case?
Python dictionaries require their keys to implement both __eq__
and __hash__
methods, and Python's data model requires that:
x == y
then hash(x) == hash(y)
Numpy's ndarray
class overrides __eq__
to support elementwise comparison and broadcasting. This means that for numpy arrays x
and y
, x == y
is not a boolean but another array. This in itself probably rules out ndarray
s functioning correctly as dictionary keys.
Even ignoring this quirk of ndarray.__eq__
, it would be tricky to come up with a (useful) implementation of ndarray.__hash__
. Since the data in a numpy array is mutable, we could not use that data to calculate __hash__
without violating the requirement that the hash of an object does not change during its lifetime.
There is nothing wrong with defining __hash__
for mutable objects provided that the hash itself does not change during the object's lifetime. Similarly, dictionary keys can be mutable provided they implement __hash__
and the hash is immutable. E.g. simple user-defined classes are mutable but can still be used as dictionary keys.
This scalar array
is regular array with a 0d shape. Otherwise there's nothing unique about it.
In [46]: x=np.array(10)
In [47]: x
Out[47]: array(10)
In [48]: x[...]=100
In [49]: x
Out[49]: array(100)
You have to extract the number from the array:
In [53]: {}.get(x)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-53-19202767b220> in <module>()
----> 1 {}.get(x)
TypeError: unhashable type: 'numpy.ndarray'
In [54]: {}.get(x.item())
In [58]: {}.get(x[()])
Looking at the hash
methods
In [65]: x.__hash__ # None
In [66]: x.item().__hash__
Out[66]: <method-wrapper '__hash__' of int object at 0x84f2270>
In [67]: x[()].__hash__
Out[67]: <method-wrapper '__hash__' of numpy.int32 object at 0xaaab42b0>