dict的查找功能如何工作?

时间:2018-03-27 23:07:29

标签: python dictionary hash

众所周知,可变类型不能成为字典的关键。

但是如果你使用说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]

我在print中添加了__hash__以找出正在进行哈希处理的内容以及何时调用该函数。

在抛出KeyError之前,会打印c的内容,表示c只是经过哈希处理。现在不应该只检查这个哈希值是否是其中一个键的哈希值?为什么会出现关键错误?

如果还要逐个哈希所有密钥以确定其中一个密钥是否散列相同的散列值,则查询不应该在下面的代码中工作?

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的半鲁棒散列函数的可变密钥,是否可能?

1 个答案:

答案 0 :(得分:0)

如何将记录存储在内存中?(简化版)

  • 对于dict中的每个键,计算hash,然后键和值都存储在由哈希定义的位置
  • 如果多个密钥具有相同的散列(或者具有指向同一存储目标的散列),则该位置将存在键值对列表

如何从内存中读取dict值?(简化版)

  • 计算密钥的hash,并根据该哈希计算内存中的位置
  • 从该位置逐个读取键值对,并使用==运算符
  • 与搜索到的键进行比较

<强>结论

要在密码中找到一个密钥(称之为key1),该密码应包含一个密钥(称之为key2),其中hash(key1) == hash(key2) and key1 == key2

那么为什么可变键是个坏主意?

因为在将密钥写入dict时会计算hash(key),并且它在该时间点与key的值匹配,但如果key是可变的,并且您在将其变异时它在dict中,dict不会重新计算hash(key),因此将无法再找到密钥。