如果一方继承另一方,__ eq__的执行顺序是什么?

时间:2019-05-07 12:20:36

标签: python python-3.x

最近,我发现关于__eq__方法执行顺序的一种看似奇怪的行为,如果比较的一面是从另一面继承的对象。

在一个公认的学术示例中,我已经在Python 3.7.2中进行了尝试。通常,给定相等比较a == b,如果第一次调用返回a.__eq__,我希望首先调用b.__eq__,然后调用NotImplemented。但是,如果ab是同一类层次结构的一部分,则情况似乎并非如此。考虑以下示例:

class A(object):
  def __eq__(self, other):
    print("Calling A({}).__eq__".format(self))
    return NotImplemented

class B(A):
  def __eq__(self, other):
    print("Calling B({}).__eq__".format(self))
    return True

class C(object):
  def __eq__(self, other):
    print("Calling C({}).__eq__".format(self))
    return False

a = A()
b = B()
c = C()

print("a: {}".format(a)) # output "a: <__main__.A object at 0x7f8fda95f860>"
print("b: {}".format(b)) # output "b: <__main__.B object at 0x7f8fda8bcfd0>"
print("c: {}".format(c)) # output "c: <__main__.C object at 0x7f8fda8bcef0>"

a == a # case 1

a == b # case 2.1
b == a # case 2.2

a == c # case 3.1
c == a # case 3.2

在情况1中,我希望a.__eq__被调用两次,这也是我得到的:

Calling A(<__main__.A object at 0x7f8fda95f860>).__eq__
Calling A(<__main__.A object at 0x7f8fda95f860>).__eq__

但是,在2.1和2.2的情况下,b.__eq__总是首先执行,无论它位于比较的哪一边:

Calling B(<__main__.B object at 0x7f8fda8bcfd0>).__eq__ # case 2.1
Calling B(<__main__.B object at 0x7f8fda8bcfd0>).__eq__ # case 2.2

然后在情况3.1和3.2中,如我所料,首先再次评估左侧:

Calling A(<__main__.A object at 0x7f8fda95f860>).__eq__ # case 3.1
Calling C(<__main__.C object at 0x7f8fda8bcef0>).__eq__ # case 3.1
Calling C(<__main__.C object at 0x7f8fda8bcef0>).__eq__ # case 3.2

似乎,如果比较的对象彼此相关,则始终首先评估子类对象的__eq__。这种行为背后是否有更深层的推理?如果是这样,这是否记录在某处?据我所知,PEP 207没有提到这种情况。还是我可能在这里遗漏了一些明显的东西?

1 个答案:

答案 0 :(得分:18)

来自the official documentation for __eq__

  

如果操作数是不同类型的,并且右侧操作数的类型是左侧操作数类型的直接或间接子类,则右侧操作数的反射方法具有优先权,否则左侧操作数的方法具有优先权。