The Python Oracle

Why/When in Python does `x==y` call `y.__eq__(x)`?

This video explains
Why/When in Python does `x==y` call `y.__eq__(x)`?

--

Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn

--

Track title: CC O Beethoven - Piano Sonata No 3 in C

--

Chapters
00:00 Question
03:32 Accepted answer (Score 33)
04:50 Answer 2 (Score 6)
05:18 Answer 3 (Score 1)
06:19 Answer 4 (Score 1)
09:16 Thank you

--

Full question
https://stackoverflow.com/questions/2281...

Accepted answer links:
[http://docs.python.org/reference/datamod...]: http://docs.python.org/reference/datamod...

Answer 2 links:
[docs]: http://docs.python.org/reference/datamod...

Answer 4 links:
[Language Reference]: http://docs.python.org/reference/datamod...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #comparison #operatoroverloading

#avk47



ACCEPTED ANSWER

Score 33


You're missing a key exception to the usual behaviour: when the right-hand operand is an instance of a subclass of the class of the left-hand operand, the special method for the right-hand operand is called first.

See the documentation at:

http://docs.python.org/reference/datamodel.html#coercion-rules

and in particular, the following two paragraphs:

For objects x and y, first x.__op__(y) is tried. If this is not implemented or returns NotImplemented, y.__rop__(x) is tried. If this is also not implemented or returns NotImplemented, a TypeError 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.




ANSWER 2

Score 6


Actually, in the docs, it states:

[__cmp__ is c]alled by comparison operations if rich comparison (see above) is not defined.

__eq__ is a rich comparison method and, in the case of TestCmp, is not defined, hence the calling of __cmp__




ANSWER 3

Score 1


Is this not documented in the Language Reference? Just from a quick look there, it looks like __cmp__ is ignored when __eq__, __lt__, etc are defined. I'm understanding that to include the case where __eq__ is defined on a parent class. str.__eq__ is already defined so __cmp__ on its subclasses will be ignored. object.__eq__ etc are not defined so __cmp__ on its subclasses will be honored.

In response to the clarified question:

I know that __eq__ is called in preferecne to __cmp__, but I'm not clear why y.__eq__(x) is called in preference to x.__eq__(y), when the latter is what the docs state will happen.

Docs say x.__eq__(y) will be called first, but it has the option to return NotImplemented in which case y.__eq__(x) is called. I'm not sure why you're confident something different is going on here.

Which case are you specifically puzzled about? I'm understanding you just to be puzzled about the "b" == tsc and tsc == "b" cases, correct? In either case, str.__eq__(onething, otherthing) is being called. Since you don't override the __eq__ method in TestStrCmp, eventually you're just relying on the base string method and it's saying the objects aren't equal.

Without knowing the implementation details of str.__eq__, I don't know whether ("b").__eq__(tsc) will return NotImplemented and give tsc a chance to handle the equality test. But even if it did, the way you have TestStrCmp defined, you're still going to get a false result.

So it's not clear what you're seeing here that's unexpected.

Perhaps what's happening is that Python is preferring __eq__ to __cmp__ if it's defined on either of the objects being compared, whereas you were expecting __cmp__ on the leftmost object to have priority over __eq__ on the righthand object. Is that it?




ANSWER 4

Score 1


As I know, __eq__() is a so-called “rich comparison” method, and is called for comparison operators in preference to __cmp__() below. __cmp__() is called if "rich comparison" is not defined.

So in A == B:
If __eq__() is defined in A it will be called
Else __cmp__() will be called

__eq__() defined in 'str' so your __cmp__() function was not called.

The same rule is for __ne__(), __gt__(), __ge__(), __lt__() and __le__() "rich comparison" methods.