为何==运算符在所有比较魔术方法返回NotImplemented时不报错?如何阻止类间==比较?
为什么
==有默认 fallback 而其他比较运算符没有? 这个差异其实是Python对不同运算符语义的设计决定的:
对于
==和!=:Python认为“对象是否相等”有一个最基础的默认逻辑——对象标识(内存地址)是否相同。当双方的__eq__(或__ne__)都返回NotImplemented时,解释器会自动 fallback 到用is运算符的逻辑来判断:如果是同一个对象(内存地址相同)则返回True,否则返回False。结合你给的例子来看:
- 执行
Foo() == Bar()时,先调用Foo.__eq__返回NotImplemented,接着Python尝试调用Bar.__eq__也返回NotImplemented,于是触发默认的对象标识比较——两个是不同类的实例,内存地址不同,所以返回False,因此assert not Foo() == Bar()能通过。 - 执行
f == f时,两次调用Foo.__eq__都返回NotImplemented,此时默认逻辑检查到是同一个对象,返回True,所以断言成立。
- 执行
对于
<、<=等排序类运算符:这类运算符的语义没有统一的“默认规则”——两个不同类的对象,谁大谁小是没有天然定义的,Python无法给出合理的默认行为,所以当双方的重载方法都返回NotImplemented时,直接抛出TypeError。
如何阻止特定类对象间的
==比较? 如果不想让解释器 fallback 到对象标识比较,你需要主动在__eq__方法中抛出TypeError,而不是返回NotImplemented。比如:
class Foo: def __eq__(self, other): # 禁止和Bar实例进行==比较 if isinstance(other, Bar): raise TypeError("不支持Foo和Bar实例之间的==比较") # 和同类型实例的自定义比较逻辑 if isinstance(other, Foo): # 比如比较实例属性 return self.__dict__ == other.__dict__ # 其他未知类型,返回NotImplemented让Python尝试对方的__eq__ return NotImplemented class Bar: def __eq__(self, other): if isinstance(other, Foo): raise TypeError("不支持Bar和Foo实例之间的==比较") if isinstance(other, Bar): return self.__dict__ == other.__dict__ return NotImplemented
这样当你执行Foo() == Bar()时,会直接抛出TypeError,完全阻止了比较操作,不会走到默认的对象标识判断步骤。
内容的提问来源于stack exchange,提问作者tburette
相关产品推荐
相关产品推荐

