<p>首先:<a href="https://docs.python.org/3.5/library/functions.html#hash" rel="noreferrer">hash</a>函数的文档中明确记录了该行为:</p>
<blockquote>
<p><strong><code>hash(object)</code></strong></p>
<p>Return the hash value of the object (if it has one). Hash values are
integers. They are used to quickly compare dictionary keys during a
dictionary lookup. <strong>Numeric values that compare equal have the same
hash value (even if they are of different types, as is the case for <code>1</code>
and <code>1.0</code>).</strong></p>
</blockquote>
<p>其次,在<a href="https://docs.python.org/3.5/reference/datamodel.html#object.__hash__" rel="noreferrer">^{<cd1>}</a>的文档中指出了散列的限制</p>
<blockquote>
<p><strong><code>object.__hash__(self)</code></strong></p>
<p>Called by built-in function <a href="https://docs.python.org/3.5/library/functions.html#hash" rel="noreferrer"><code>hash()</code></a> and for operations on members of
hashed collections including <code>set</code>, <code>frozenset</code>, and <code>dict. __hash__()</code>
should return an integer. <strong>The only required property is that objects
which compare equal have the same hash value;</strong></p>
</blockquote>
<p>这不是python独有的。Java也有同样的警告:如果您实现了<code>hashCode</code>,那么为了让事情正常运行,您必须以这样一种方式实现它:<code>x.equals(y)</code>意味着<code>x.hashCode() == y.hashCode()</code></p>
<p>因此,python决定<code>1.0 == 1</code>保持不变,因此它被迫<em>为<code>hash</code>提供一个实现,以便<code>hash(1.0) == hash(1)</code>。副作用是<code>1.0</code>和<code>1</code>的行为与<code>dict</code>键的行为完全相同,因此这种行为是正确的</p>
<p>换句话说,行为本身不必以任何方式使用或有用<strong>这是必要的</strong>。如果没有这种行为,您可能会意外地覆盖不同的密钥</p>
<p>如果我们有<code>1.0 == 1</code>但是<code>hash(1.0) != hash(1)</code>,我们仍然可以有一个<em>碰撞</em>。如果<code>1.0</code>和<code>1</code>发生冲突,<code>dict</code>将使用相等来确定它们是否是同一个键,<em>kaboom</em>即使您希望它们不同,也会覆盖该值</p>
<p>避免这种情况的唯一方法是使用<code>1.0 != 1</code>,这样<code>dict</code>即使在发生冲突的情况下也能够区分它们。但是,人们认为拥有<code>1.0 == 1</code>比避免你看到的行为更重要,因为你实际上从来没有使用<code>float</code>和<code>int</code>作为字典键</p>
<p>由于python试图通过在需要时自动转换数字(例如<code>1/2 -> 0.5</code>)来隐藏数字之间的区别,因此即使在这种情况下也可以反映这种行为。它与python的其他部分更加一致</p>
<hr/>
<p>这种行为会出现在<em>任何</em>实现中,其中键的匹配至少部分地(如在哈希映射中)基于比较</p>
<p>例如,如果一个<code>dict</code>是使用红黑树或其他类型的平衡BST实现的,当查询键<code>1.0</code>时,与其他键的比较将返回与<code>1</code>相同的结果,因此它们仍然以相同的方式工作</p>
<p>散列映射需要更加小心,因为用于查找密钥项的是散列值,只有在之后才进行比较。因此,违反上述规则意味着您将引入一个很难发现的错误,因为有时<code>dict</code>可能会像您预期的那样工作,而在其他时候,当大小发生变化时,它将开始表现不正确</p>
<hr/>
<p>注意,<em>将有一种方法来解决这个问题:为字典中插入的每种类型都有一个单独的hash-map/BST。通过这种方式,不同类型的对象之间不会发生任何冲突,并且当参数具有不同类型时,<code>==</code>的比较方式也无关紧要</p>
<p>然而,这将使实现复杂化,这可能是低效的,因为哈希映射必须保留相当多的空闲位置才能有O(1)个访问时间。如果它们变得太满,性能就会下降。拥有多个哈希映射意味着浪费更多空间,而且在开始实际查找密钥之前,您需要首先选择要查看的哈希映射</p>
<p>如果使用BST,则必须首先查找类型,然后执行第二次查找。因此,如果您要使用许多类型,那么最终的工作量将是原来的两倍(并且查找将需要O(logn)而不是O(1))</p>