什么时候 d1==d2 不等于 d1.__eq__(d2)?

the*_*cho 4 python python-3.x

根据文档(Python 3.8):

默认情况下,通过使用 来object实现,在比较错误的情况下返回: 。__eq__()isNotImplementedTrue if x is y else NotImplemented

并且:

运算符号与方法名的对应关系如下: [...]x==y调用x.__eq__(y)

所以我期望

  1. ==相当于__eq__()
  2. 没有显式定义的自定义类,用于比较该类的两个不同实例时__eq__返回。然而在下面,比较返回,而返回:NotImplemented====False__eq__()NotImplemented
class Dummy():
    def __init__(self, a):
        self.a = a

d1 = Dummy(3)
d2 = Dummy(3)

d1 == d2 # False
d1.__eq__(d2) # NotImplemented
Run Code Online (Sandbox Code Playgroud)

为什么?

wim*_*wim 7

原因是,如果操作的一侧不能(或不会)提供答案,则另一侧可以在处理此比较时拥有发言权。一个常见的例子是 float/int 比较:

>>> 1 == 1.0
True
>>> (1).__eq__(1.0)
NotImplemented
>>> (1.0).__eq__(1)
True
Run Code Online (Sandbox Code Playgroud)

对于intand float,两者都不是另一个的子类,并且 anint没有任何关于它是否等于 some 的信息float。相等比较由类型处理float

如果左侧和右侧有不同的类型,并在挂钩中添加一些调试打印输出,则更容易理解:

class Left:
    def __eq__(self, other):
        print("trying Left.__eq__")
        return NotImplemented

class Right:
    def __eq__(self, other):
        print("trying Right.__eq__")
        return True
Run Code Online (Sandbox Code Playgroud)

演示:

>>> d1 = Left()
>>> d2 = Right()
>>> d1.__eq__(d2)
trying Left.__eq__
NotImplemented
>>> d2.__eq__(d1)
trying Right.__eq__
True
>>> d1 == d2  # Left.__eq__ "opts out" of the comparison, Python asks other side
trying Left.__eq__
trying Right.__eq__
True
>>> d2 == d1  # Right.__eq__ returns a result first, Left.__eq__ isn't considered
trying Right.__eq__
True
Run Code Online (Sandbox Code Playgroud)

左侧type(d1).__eq__通过返回选择退出NotImplemented,这使得右侧有处理操作的“第二次机会”。如果左侧返回False而不是返回NotImplemented,Python 根本不会尝试右侧,结果将d1 == d2False。如果双方都返回NotImplemented,就像在您的Dummy示例中一样,那么对象将被视为不相等,除非它们相同(即相同的实例)。