From 3. Data model — Python 3.12.0 documentation
These are the so-called “rich comparison” methods. The correspondence between operator symbols and method names is as follows:
x<y
callsx.__lt__(y)
,x<=y
callsx.__le__(y)
,x==y calls x.__eq__(y)
,x!=y
callsx.__ne__(y)
,x>y
callsx.__gt__(y)
, andx>=y
callsx.__ge__(y)
.
However, this does not appear to cover the case where y
is an instance of a subclass of x
. In these cases, y.__eq__(x)
is tried first (so that subclasses can specialize the behaviour from either side of the operator).
I modified the example to try to make the issue as clear as possible:
def _log(lhs, rhs):
print(f'compare {lhs} == {rhs}')
class A:
def __str__(self):
return '<A instance>'
def __eq__(self, other):
_log(self, other)
return True
class B(A):
def __str__(self):
return '<B instance>'
def __eq__(self, other):
_log(self, other)
return False
class C: # note, not related by inheritance
def __str__(self):
return '<C instance>'
def __eq__(self, other):
_log(self, other)
return False
a, b, c = A(), B(), C()
The results are clear:
>>> a == b
compare <B instance> == <A instance>
False
>>> a == c
compare <A instance> == <C instance>
True