矩阵作为字典键

6

我刚开始使用 numpy 和它的 matrix 模块(非常非常有用!),我想要将一个矩阵对象作为字典的键,所以我查看了一下 matrix 是否实现了 __hash__ 方法:

>>> from numpy import matrix
>>> hasattr(matrix, '__hash__')
True

它确实可以!很好,这意味着它可以成为字典的键:

>>> m1 = matrix('1 2 3; 4 5 6; 7 8 9')
>>> m1
matrix([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
>>> m2 = matrix('1 0 0; 0 1 0; 0 0 1')
>>> m2
matrix([[1, 0, 0],
        [0, 1, 0],
        [0, 0, 1]])
>>> matrix_dict = {m1: 'first', m2: 'second'}

做得好!现在,让我们继续测试:

>>> matrix_dict[m1]
'first'
>>> matrix_dict[matrix('1 2 3; 4 5 6; 7 8 9')]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: matrix([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

什么?所以说,它适用于相同的矩阵,但对于具有完全相同内容的另一个矩阵却不起作用?让我们看看__hash__返回的是什么:

>>> hash(m1)
2777620
>>> same_as_m = matrix('1 2 3; 4 5 6; 7 8 9')
>>> hash(same_as_m)
-9223372036851998151
>>> hash(matrix('1 2 3; 4 5 6; 7 8 9')) # same as m too
2777665

因此,来自numpymatrix__hash__方法会为相同的matrix返回不同的值。

这样没关系吗?那么,这意味着它不能用作字典键吗?如果不能使用,为什么还要实现__hash__


4
Python对象默认情况下是可哈希的 - 对于不可哈希的类,您需要禁用它。这可能只是 numpy 遗漏了这一点。 - millimoose
矩阵是ndarray的基础,它们默认也是可哈希的 - 我认为您使用它们时会遇到相同的问题。 - John Lyon
@jozzas,我很惊讶可以将矩阵用作字典键,因为我知道ndarrays不能用作键,而矩阵是ndarray的子类。 - Bi Rico
1个回答

9

如果将一个可变对象用作字典的键,就会出现问题,因为一旦更改数据,其哈希值就应该随之更改,但插入时使用的值将被保留。

在我的测试中,Python 3.2.2 中的 numpy 会引发 TypeError:

TypeError: unhashable type: 'matrix'

但是在Python 2.7中,它仍允许哈希,但是当您更改数据时,哈希值永远不会更改,因此作为字典键相当无用,因为添加到字典中的许多matrix对象具有相同的哈希值,这将降低哈希表,所以插入将变为O(n^2)而不是O(1)

也许他们没有删除哈希值是为了避免在Python 2.x上破坏某些API,但是不要依赖它!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接