如何使包含numpy数组的元组可哈希化?

Dem*_*nto 1 tuples numpy python-3.x hashable

使numpy数组可哈希化的一种方法是将其设置为只读。过去这对我有用。但是,当我在元组中使用这样的numpy数组时,整个元组不再是可哈希化的,这是我不理解的。这是我整理来说明问题的示例代码:

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}
Run Code Online (Sandbox Code Playgroud)

首先,我创建一个简单的numpy数组并将其设置为只读。然后,将其添加到元组,并检查它是否仍是只读的(它是)。

当我想使用元组作为字典中的键时,出现错误TypeError: unhashable type: 'numpy.ndarray'

这是我的示例代码的输出:

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

我该怎么做才能使我的元组可哈希化?为什么Python首先显示这种行为?

use*_*ica 7

你声称

使numpy数组可哈希化的一种方法是将其设置为只读

但这不是真的。将数组设置为只读只会使其变为只读。由于多种原因,它不会使数组成为可散列的。

第一个原因是writeable标记设置为的数组False仍然可变。首先,您始终可以writeable=True重新设置并继续对其进行写入,或者进行更多奇特的操作,例如,shape即使writeableis 仍然重新分配它False。其次,即使不接触数组本身,也可以通过另一个具有的视图来对其数据进行突变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])
Run Code Online (Sandbox Code Playgroud)

其次,为了使散列性有意义,对象必须首先是相等的 - ==必须返回布尔值,并且必须是等价关系。NumPy数组不这样做。哈希值的目的是快速定位相等的对象,但是当您的对象甚至没有内置的相等性概念时,提供哈希就没有多大意义。


您不会获得带有数组的可哈希元组。您甚至都不会获得可散列的数组。您可以获得的最接近的结果是将数组数据的其他表示形式放入元组中。

  • +1,感谢您对内部结构的澄清。如果散列数组的想法不在表中,我将不得不首先将其转换为字符串。 (2认同)

And*_*den 6

散列 numpy 数组的最快方法可能是 tostring

In [11]: %timeit hash(y.tostring())
Run Code Online (Sandbox Code Playgroud)

你可以做的是而不是使用元组定义一个类:

class KeySet(object):
    def __init__(self, i, arr):
        self.i = i
        self.arr = arr
    def __hash__(self):
        return hash((self.i, hash(self.arr.tostring())))
Run Code Online (Sandbox Code Playgroud)

现在你可以在字典中使用它:

In [21]: ks = KeySet(0, npArray)

In [22]: myDict = {ks: 1}

In [23]: myDict[ks]
Out[23]: 1
Run Code Online (Sandbox Code Playgroud)

  • 这感觉很Pythonic,感谢您的快速回答!我还可以使用包装 numpy.fromstring() 的函数将其转换回来,稍后我将需要它。 (3认同)