<p>这是一个奇怪的命运。一些CPython的机器阻碍了你。这三个问题是:</p>
<ol>
<li>支持<code>dict</code>的数组的初始大小为8<sup>[1]</sup></li>
<li>CPython中的所有对象的内存地址都是模8<sup>[2]</sup></li>
<li><code>dict</code>类有一个优化,检查键是否是同一个对象,如果为真则停止在那里(否则它将根据<code>__eq__</code>方法检查它们是否相等)<sup>[3]</sup></li>
</ol>
<p>这意味着,尽管对象总是生成不同的哈希值,但要检查的后备数组的第一个槽是相同的。如果不是,你会得到一个密钥错误,因为插槽是空的。<code>dict</code>然后决定它有正确的键,因为它有完全相同的对象,而不仅仅是一个相等的对象。在</p>
<pre><code>class PhonyHash:
_hash = 1
def __hash__(self):
return self._hash
p = PhonyHash()
d = {p: "val"}
print(p in d) # True
p._hash = 2
print(p in d) # False
p._hash = 9 # 9 % 8 == 1
print(p in d) # True
</code></pre>
<h3>CPython源的链接</h3>
<ol>
<li><code>dict</code><a href="https://github.com/python-git/python/blob/master/Include/dictobject.h#L69" rel="nofollow">struct</a>定义了<code>ma_table</code>,它以<code>ma_smalltable</code>开头,长度为<a href="https://github.com/python-git/python/blob/master/Include/dictobject.h#L48" rel="nofollow">PyDict_MinSize</a>。在</li>
<li>这在<a href="https://github.com/python-git/python/blob/master/Objects/obmalloc.c#L81" rel="nofollow">Objects/obmalloc.c</a>中有记录</li>
<li>可以在查找函数<a href="https://github.com/python-git/python/blob/master/Objects/dictobject.c#L310" rel="nofollow">here</a>和<a href="https://github.com/python-git/python/blob/master/Objects/dictobject.c#L346" rel="nofollow">here</a>中看到</li>
</ol>