【问题标题】:Overriding Python's Hashing Function in Dictionary在字典中覆盖 Python 的散列函数
【发布时间】:2012-11-10 23:17:39
【问题描述】:

我正在尝试为一些我将散列到字典中的对象创建自定义散列函数。散列函数是唯一的(不是标准的 Python 函数)。这对我来说非常重要:使用独特的功能。每个键的值都是一个列表。

假设我覆盖了__hash__ 并最终得出了一个对象的正确哈希数。会:

dict = {}
dict[number_here] = value

将值散列到位置编号number_here,还是仍然在 Python 的哈希表将为该编号计算的位置?

打印dict 只显示项目而不是它们的位置。但是,当我执行hash(4) 时,结果是 4。所以我假设这意味着整数被散列到它们各自的位置?

如果我错了,有人可以验证我的发现或向我解释吗?

【问题讨论】:

  • 这个视频可能会让事情更清楚一点:t.co/ZqEWs8MD
  • @ShawnChin:这就是为什么只链接答案(和 cmets)不受欢迎的原因。

标签: python hash dictionary hashtable


【解决方案1】:

Martijn Pieters 给出了很好的答案。我只是想补充一点,CPython source 有很好的文档记录,也是查看 Python Dictionary 实现细节的好地方。上次我查了一下,相关的 cmets 在第 33-135 行。

【讨论】:

    【解决方案2】:

    python dict 实现使用哈希值来基于键稀疏存储值并避免该存储中的冲突。它使用hash() 的结果作为起点,它不是最终位置。

    因此,虽然hash(4) 返回4,但在底层C 结构中的确切“位置”还基于已经存在的其他 键以及当前表的大小。例如,python 哈希表会根据需要(添加的项目)调整大小。

    由于 dict 没有顺序,这不是你需要担心的事情,也不需要影响。如果您需要在 dict 中排序,请改用 collections.OrderedDict() 实现,它会单独跟踪排序。

    python哈希表实现细节

    您可能想了解哈希表如何在 Wikipedia 上工作; Python 使用开放寻址来实现。

    当在表中选择一个槽时,取哈希值(整数)和当前表大小的模数,因此在大小为 32 的表上,所以键 45,哈希值 45 将最初存储在插槽 14 中。

    如果发生冲突(槽 14 中已经存储了其他内容,并且不是整数 45),则槽值扰乱,直到找到空槽或相同而是找到了密钥。扰动是用公式完成的:

    perturb = slot = hash
    while slot_is_full and item_in_slot_is_not_equal_to_key:
        slot = (5*slot) + 1 + perturb
        perturb >>= 5
    

    因此,当发生冲突时,会以越来越小的步长选择另一个槽,直到它扫描整个表。请注意,如果需要,表格已经调整大小以腾出空间。

    为了使其正常工作,自定义类型需要__hash__() 方法并且需要实现__eq__() 以确定两个实例是否代表相同的键。匹配哈希值不够。要让dict 实现考虑两个实例来表示完全相同的键,它们的哈希值必须匹配,并且它们必须为== 相等运算符返回True。此类对象被视为hashable

    (对于 Python 2.x,实现 __cmp__() hook 代替实现 __eq__();在 Python 3 中已删除对此的支持)。

    【讨论】:

    • 我有一个问题:在我的机器上 hash('abc') == hash(-1600925533)。我可以有一个包含两个值作为键的字典。不应该有某种哈希冲突吗?还是python python使用其他一些哈希函数,而不是内置的hash()?
    • @MartijnPieters 谢谢。我希望 Python 处理冲突,如果它重新排序也没关系。但是如果两个不同的对象返回hash 4,它们肯定会一直hash到同一个key,对吧?
    • 哈希冲突可能而且确实会发生,哈希表实现能够处理这些冲突。
    • @Darksky:不,除非这些键相等hash(key1) == hash(key2) 不足以被视为同一个键。 key1 == key2 也必须为真。
    猜你喜欢
    • 1970-01-01
    • 2017-09-19
    • 2016-09-03
    • 1970-01-01
    • 2015-05-03
    • 2010-11-12
    • 2021-01-14
    • 1970-01-01
    • 2021-03-18
    相关资源
    最近更新 更多