矩阵作为字典键
我刚开始使用 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
所以,numpy
中的 matrix
的 __hash__
方法对于同一个 matrix
返回了不同的值。
这对吗?这是不是意味着它不能用作字典的键?如果不能用,那它为什么还要实现 __hash__
呢?
1 个回答
9
把一个可变对象当作字典的键是错误的,因为一旦你改变了这个对象的数据,它的哈希值就应该改变,但插入时使用的值却会保持不变。
在我测试的过程中,Python 3.2.2的numpy会抛出一个类型错误:
TypeError: unhashable type: 'matrix'
但是在Python 2.7中,它仍然允许进行哈希操作,不过当你改变数据时,哈希值却不会改变。因此,把它作为字典的键就没什么用,因为很多matrix
对象被添加到字典中时哈希值相同,这样会导致哈希表的性能下降,插入操作的复杂度会变成O(n^2)
,而不是O(1)
。
也许他们没有去掉哈希值是为了避免破坏Python 2.x中的某些API,但你可千万别依赖这个!