In python 2.7.6, suppose that I have a class that defines __eq__
and a subclass
thereof:
>>> class A(object):
... def __eq__(self,other):
... print self.__class__,other.__class__
... return True
...
>>> class B(A):
... pass
...
Now I create an object of each class, and want to compare them:
>>> a = A()
>>> b = B()
>>> a==b
The result I get:
<class '__main__.B'> <class '__main__.A'>
This shows that the interpreter is calling b.__eq__(a)
, instead of a.__eq__(b)
as
expected.
The documentation states (emphasis added):
For objects
x
andy
, firstx.__op__(y)
is tried. If this is not implemented or returnsNotImplemented
,y.__rop__(x)
is tried. If this is also not implemented or returnsNotImplemented
, aTypeError
exception is raised. But see the following exception:Exception to the previous item: if the left operand is an instance of a built-in type or a new-style class, and the right operand is an instance of a proper subclass of that type or class and overrides the base’s
__rop__()
method, the right operand’s__rop__()
method is tried before the left operand’s__op__()
method.This is done so that a subclass can completely override binary operators. Otherwise, the left operand’s
__op__()
method would always accept the right operand: when an instance of a given class is expected, an instance of a subclass of that class is always acceptable.
Since the subclass B
does not override the __eq__
operator, shouldn't a.__eq__(b)
be called instead of b.__eq__(a)
? Is this expected behavior, or a bug? It is contrary to the documentation as I read it: am I misreading the documentation or missing something else?
Some related questions:
This answer quotes the documentation that I quoted above. In that case the final question involved a comparison between an object of built in type (1) and an an instance of a new style class. Here, I'm specifically comparing an instance of a parent class with an instance of a subclass which does not override the
rop()
method of its parent (in this case,__eq__
is bothop()
androp()
).In this case, python actually does call
b.__eq__(a)
instead ofa.__eq__(b)
first, even though classB
does not explicitly overrideA
.