Don’t mix up apples and oranges
The problem
I’m playing with the __eq__
operator and the NotImplemented
value.
I’m trying to understand what’s happen when obj1.__eq__(obj2)
returns NotImplemented
and obj2.__eq__(obj1)
also returns NotImplemented
.
According to the answer to Why return NotImplemented instead of raising NotImplementedError, and the detailed article How to override comparison operators in Python in the "LiveJournal" blog, the runtime should fall back to the built-in behavior (which is based on identity for ==
and !=
).
Code sample
But, trying the example bellow, it seems that I have multiple calls to __eq__
for each pair of objects.
class Apple(object):
def __init__(self, color):
self.color = color
def __repr__(self):
return "<Apple color='{color}'>".format(color=self.color)
def __eq__(self, other):
if isinstance(other, Apple):
print("{self} == {other} -> OK".format(self=self, other=other))
return self.color == other.color
print("{self} == {other} -> NotImplemented".format(self=self, other=other))
return NotImplemented
class Orange(object):
def __init__(self, usage):
self.usage = usage
def __repr__(self):
return "<Orange usage='{usage}'>".format(usage=self.usage)
def __eq__(self, other):
if isinstance(other, Orange):
print("{self} == {other}".format(self=self, other=other))
return self.usage == other.usage
print("{self} == {other} -> NotImplemented".format(self=self, other=other))
return NotImplemented
>>> apple = Apple("red")
>>> orange = Orange("juice")
>>> apple == orange
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
False
Expected behavior
I expected to have only:
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
Then falling back to identity comparison id(apple) == id(orange)
-> False
.