编程中级 Python 开发者

在Python中,比较运算符 '==' 和方法 __eq__ 的功能是怎样定义的?如何可以改变自定义类的比较行为?

用 Hintsage AI 助手通过面试

答案。

问题背景:

在Python中,通过运算符 '==' 进行对象值的比较,底层调用方法 eq。该方法的默认行为继承自object类,比较对象的身份(对于大多数类来说)。

问题:

当我们希望自定义类的实例能够有意义地进行比较(例如,两个不同的Person对象如果数据相同就视为相等),标准行为是不够的——我们需要明确地定义比较的方式。

解决方案:

要改变 '==' 的行为,需要在自定义类中重写方法 eq。如果类需要可哈希,还需要重写 hash

示例代码:

class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True

关键特性:

  • '==' 调用 eq
  • 在没有 eq 的对象比较时,将比较它们的身份 (id)。
  • 为了正确处理集合/字典,还需要实现 hash

复杂问题。

比较 '==' 对不同类型对象总是对称的吗?

不一定——如果第一个对象返回 NotImplemented,则会调用反向比较。否则可能会导致不对称。

class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False

如果没有实现 eq,同一用户自定义类的对象会如何比较?

将比较身份 (id)(内存中的身份,而不是属性值)。

class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False

可以不定义 hash 而定义 eq 吗?对于应作为字典键的对象?

不行。如果 eq 被修改,建议也定义 hash,否则对象将变为不可哈希的 (在用作键时会出现 TypeError)。

class Foo: def __eq__(self, other): return True # hash 继承自 object,但行为将是不可预知的 # 最好明确指定 __hash__

常见错误和反模式

  • 在需要字典/集合的键的地方实现 eq 但不实现 hash
  • 与其他类型对象比较时的错误(应返回 NotImplemented,而不是 False)。
  • eqhash 的不一致定义导致哈希结构中不正确的行为。

实例分享

负面案例

在设计 ValueObject 类时,团队没有意识到只实现了 eq,而没有实现 hash。尝试将对象用作字典中的键或集合中的元素时,抛出了 TypeError 异常。

优点:

快速引入自定义比较。

缺点:

无法在集合和字典中使用对象,调试复杂。

正面案例

在另一个项目中,开发人员明确实现了两个方法—— eqhash,严格遵循规则:如果两个对象在 eq 上相等,它们的哈希值也必须相等。

优点:

哈希结构正常工作,行为一致,易于维护。

缺点:

失去灵活性:值相等的对象在哈希容器中不可区分。