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
xandy, 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, aTypeErrorexception 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 classBdoes not explicitly overrideA.