众所周知,可变类型不能是字典的关键。
但是,如果您使用的是C ,则常规地图让您使用向量和数组作为地图键,因为将常规地图实现为树。
但是,C 还可以让您使用数组作为无序地图的钥匙,它在精神上更接近Python词典,因为它只要您提供类型的哈希功能,它就不知道如何提供键到哈希。
所以我想知道只要您提供__hash__
方法,Python是否会让您做同样的事情。
In [1]: b = {}
In [2]: class hlist(list):
...: def __hash__(self):
...: temp = []
...: for item in self:
...: print item
...: temp.append(item)
...: return hash(tuple(temp))
...:
In [3]: a = hlist([1,2,3,4])
In [4]: c = hlist([1,2,3,4])
In [5]: b[a] = "car"
1
2
3
4
In [6]: b[c]
1
2
3
4
Out[6]: 'car'
In [7]: a.append(5)
In [8]: b[c]
1
2
3
4
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-8-013e994efe63> in <module>()
----> 1 b[c]
KeyError: [1, 2, 3, 4]
我在__hash__
内添加了print
,以找出正在调用的函数以及何时调用函数。
就在抛出KeyError
之前,打印了c
的内容,表明c
只是hash。现在不应该仅检查一个键是否的哈希值之一?为什么会丢下密钥错误?
如果它也是一个一个一个键,以弄清楚其中一个键是否与查询不应工作的查询相同的哈希值?
In [11]: b[hlist([1,2,3,4,5])]
1
2
3
4
5
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-11-09593553a69b> in <module>()
----> 1 b[hlist([1,2,3,4,5])]
KeyError: [1, 2, 3, 4, 5]
如果您确定具有与CPP相似的半稳健哈希功能的可变键?
dict如何存储在内存中?(简化版本(
- 对于dict中的每个键,计算
hash
,然后将密钥和值存储在由哈希定义的位置
定义的位置 - 如果多个键具有相同的哈希(或指向同一存储目的地的哈希(,则该位置中将有一个键值对列表
如何从内存中读取dict值?(简化版本(
- 计算键的
hash
,并根据哈希>计算内存中的位置 - 键值对从该位置逐一读取,并与使用
==
操作员进行比较
结论
要在dict中找到键(称为 key1
(,dict应包含一个键(调用 key2
(, hash(key1) == hash(key2) and key1 == key2
。
那么,为什么Mutable键是个坏主意?
因为当键写入dict时计算hash(key)
,并且在该时间点匹配key
的值,但是如果key
是可突变的,并且在dict中进行突变,则不会重新计算hash(key)
,因此,将不再有可能找到钥匙。