You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python 2仅对旧式类禁用隐式__hash__方法?

Python新旧式类重写__eq__时的哈希行为差异原因

在任何语言中重写类的相等性方法时,都需注意避免创建与相等性逻辑不一致的哈希函数——这是字典、集合等哈希表结构能正常工作的核心前提。

Python 3与Python 2旧式类的行为

当仅重写__eq__方法时,Python 3和Python 2的旧式类会自动移除__hash__方法,此时类的实例无法作为字典的键或存入集合,直接使用会抛出错误:

class C:
    def __eq__(self, o): return "hello"
{C() : 1} # 抛出错误

Python 2新式类的行为

但Python 2中继承自object的新式类,却允许此类哈希操作:

class A(object):
    def __eq__(self, o): return "hello"

{A() : 2} # 可正常执行

这两种差异带来两个意外点:

  • 此前认为Python 3类与Python 2新式类行为一致的认知有误
  • Python 2引入新式类时似乎移除了一项安全特性

差异背后的原因

这个行为差异是Python语言演化中,对哈希与相等性一致性规则逐步严格化的结果:

  1. Python 2新式类的兼容性妥协
    Python 2推出新式类时,为了兼容大量旧代码,没有强制绑定__eq__与__hash__的逻辑。它默认沿用object类的__hash__实现——基于对象内存地址生成哈希值,哪怕用户重写了__eq__。这种设计给了开发者灵活性,但也埋下隐患:如果两个对象通过__eq__判断为相等,却因为内存地址不同拥有不同哈希值,会直接破坏哈希表的一致性,导致字典、集合出现查找失效、数据丢失等异常。

  2. Python 3的规则收紧
    到Python 3阶段,社区意识到这种灵活性带来的大量隐性bug,于是统一了规则:只要重写__eq__但未同步重写__hash__,Python会自动将该类的__hash__设为None,直接禁止哈希操作。这是一种强制的安全机制,目的是明确提醒开发者:修改相等性逻辑后,必须同步调整哈希函数,确保相等的对象一定有相同哈希值,从根源避免哈希表的异常行为。

而Python 2的旧式类之所以和Python 3行为一致,是因为旧式类沿用了早期Python的严格规则,新式类作为当时的新特性为兼容做了妥协,最终在Python 3中废弃旧式类,统一了更严谨的规范。

内容的提问来源于stack exchange,提问作者julaine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 08:52:37