CPython字典行为:为何hash相同的-1/-2未像True/1那样合并键?
CPython 字典同哈希键不覆盖的根本原因
特殊哈希值的由来
观察到的hash(-1)与hash(-2)返回值相同,是CPython针对整数类型哈希实现的历史遗留特性:
CPython内部的字典结构中,会用哈希值-1标记空槽位(代表该位置从未存入有效键值对)。为了避免某个整数计算出的真实哈希值恰好等于-1,和空槽标记发生冲突,代码中做了特殊硬编码:只要待计算的整数原本的哈希结果是-1,就强制把哈希返回值改成-2。而-2本身的原生哈希结果恰好就是-2,最终才出现两个不同整数哈希值完全撞车的现象。
字典的双流程设计:定位靠哈希,判重靠等值
大家对字典行为的常见认知误区,本质是把“键的存储定位流程”和“键的等值判定流程”混在了一起:
- 存储定位流程:字典计算某个键应该存入哪个槽位时,确实完全依托哈希值完成——通过哈希值对字典的槽位总数取模,得到键的初始存储位置,这部分逻辑完全不涉及键的实际值比较。
- 键的等值判定流程:当多个键的哈希值完全相同、被定位到同一个槽位附近时,才会触发后续的等值判断逻辑,判定这些键是不是同一个:
- 如果两个键的等值判断(通过
==运算符判断)返回True,才会判定为同一个键,触发原有键值对的覆盖逻辑。 - 如果两个键的等值判断返回
False,哪怕哈希值完全一致,也会作为独立的键存储在同位置的冲突链表中,完全不会触发覆盖。
- 如果两个键的等值判断(通过
两类观察结果的对比
对比两种同哈希场景,就能直观看到逻辑差异:
True和1的场景:二者不仅哈希值完全相同,且由于bool是int的子类,True == 1的判断结果为True,完全满足覆盖触发的等值条件,因此最终会出现键值覆盖。-1和-2的场景:虽然二者哈希值都是-2,但-1 == -2的判断结果为False,不满足等值判定的覆盖条件,因此会作为两个独立键正常存储。
设计逻辑依据
这套流程完全符合Python哈希协议的官方约定:两个判定相等的对象必须拥有相同的哈希值,但拥有相同哈希值的两个对象,不要求一定是相等的。
哈希值本质只是用来快速缩小查找范围的索引手段,从来不是判断两个对象是否等价的核心依据;等值判断才是决定两个对象能否作为同一个字典键的最终标准。
内容的提问来源于stack exchange,提问作者user459872
相关产品推荐
相关产品推荐

