使用标量ndarray作为键

时间:2017-10-09 00:05:19

标签: numpy

这有效

range(50)[np.asarray(10)]

这有效

{}.get(50)

这不是因为unhashable type: 'numpy.ndarray'

{}.get(np.asarray(50))

有没有理由为这种情况实施__hash__

2 个答案:

答案 0 :(得分:2)

Python词典需要其键来实现__eq____hash__方法,Python的数据模型要求:

  1. 对象的哈希值在其生命周期内不会改变
  2. 如果x == yhash(x) == hash(y)
  3. Numpy的ndarray课程覆盖__eq__以支持元素比较和广播。这意味着对于numpy数组xyx == y不是布尔值而是另一个数组。这本身可能会排除ndarray正确运行的字典键。

    即使忽略ndarray.__eq__的这个怪癖,提出ndarray.__hash__的(有用的)实现也会很棘手。由于numpy数组中的数据是可变的,因此我们无法使用该数据来计算__hash__,而不会违反对象的哈希值在其生命周期内不会更改的要求。

    为可变对象定义__hash__没有任何问题,前提是散列本身在对象的生命周期内不会发生变化。类似地,字典键可以是可变的,只要它们实现__hash__并且散列是不可变的。例如。简单的用户定义类是可变的,但仍可用作字典键。

答案 1 :(得分:2)

scalar array是具有0d形状的常规数组。否则没有什么独特之处。

In [46]: x=np.array(10)
In [47]: x
Out[47]: array(10)
In [48]: x[...]=100
In [49]: x
Out[49]: array(100)

您必须从数组中提取数字:

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[()])

查看hash方法

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>