【问题标题】:Using scalar ndarrays as keys使用标量 ndarrays 作为键
【发布时间】:2017-10-10 01:47:39
【问题描述】:

这行得通

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

这行得通

{}.get(50)

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

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

__hash__ 没有针对这种情况实施吗?

【问题讨论】:

  • 如果您想实际执行此操作,请参阅此问题:stackoverflow.com/questions/16589791/… 但这不是您问题的答案,为什么?
  • hash 也没有为list 实现(也不是dict)。它是为不可变的tuple 实现的。即使[50] 也是如此。字典的key 必须是不可变的。数组或列表的索引可以是可变数字。通常scalar ndarrays 没有那么有用,除了作为多维数组的副产品。

标签: numpy


【解决方案1】:

Python 字典需要它们的键来实现 __eq____hash__ 方法,而 Python 的数据模型要求:

  1. 对象的哈希值在其生命周期内不会改变
  2. 如果x == y 那么hash(x) == hash(y)

Numpy 的 ndarray 类覆盖 __eq__ 以支持元素比较和广播。这意味着对于 numpy 数组 xyx == y 不是布尔值,而是另一个数组。这本身可能会排除 ndarrays 作为字典键正常工作。

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

只要散列本身在对象的生命周期内不会改变,为可变对象定义__hash__ 并没有错。同样,字典键可以是可变的,只要它们实现__hash__ 并且哈希是不可变的。例如。简单的用户定义类是可变的,但仍可用作字典键。

【讨论】:

    【解决方案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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-23
      • 2014-04-21
      • 1970-01-01
      • 2010-10-19
      • 2014-01-01
      • 2017-05-27
      • 2014-10-16
      • 1970-01-01
      相关资源
      最近更新 更多