Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the order of execution of __eq__ if one side inherits from the other? [duplicate]

I recently stumbled upon a seemingly strange behavior regarding the order in which __eq__ methods are executed, if one side of the comparison is an object which inherits from the other.

I've tried this in Python 3.7.2 in an admittedly academic example. Usually, given an equality comparison a == b, I expect a.__eq__ to be called first, followed by b.__eq__, if the first call returned NotImplemented. However, this doesn't seem to be the case, if a and b are part of the same class hierarchy. Consider the following example:

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

In case 1, I expect a.__eq__ to be called twice and this is also what I get:

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

However, in cases 2.1 and 2.2, b.__eq__ is always executed first, no matter on which side of the comparison it stands:

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

In cases 3.1 and 3.2 then, the left-hand side is again evaluated first, as I expected:

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

It seems that, if the compared objects are related to each other, __eq__ of the object of the child class is always evaluated first. Is there a deeper reasoning behind this behavior? If so, is this documented somewhere? PEP 207 doesn't mention this case, as far as I can see. Or am I maybe missing something obvious here?

like image 656
Andreas Avatar asked May 07 '19 12:05

Andreas


People also ask

What is the __ eq __ method?

Summary. Implement the Python __eq__ method to define the equality logic for comparing two objects using the equal operator ( == )

What does __ class __ mean in Python?

__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .

What is __ INT __ in Python?

The __int__ method is called to implement the built-in int function. The __index__ method implements type conversion to an int when the object is used in a slice expression and the built-in hex , oct , and bin functions.


1 Answers

From the official documentation for __eq__ :

If the operands are of different types, and right operand’s type is a direct or indirect subclass of the left operand’s type, the reflected method of the right operand has priority, otherwise the left operand’s method has priority.

like image 61
Lenormju Avatar answered Oct 16 '22 20:10

Lenormju