The Python docs clearly state that x==y
calls x.__eq__(y)
. However it seems that under many circumstances, the opposite is true. W开发者_JAVA百科here is it documented when or why this happens, and how can I work out for sure whether my object's __cmp__
or __eq__
methods are going to get called.
Edit: Just to clarify, 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.
>>> class TestCmp(object):
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestEq(object):
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tc = TestCmp()
>>> te = TestEq()
>>>
>>> 1 == tc
__cmp__ got called
True
>>> tc == 1
__cmp__ got called
True
>>>
>>> 1 == te
__eq__ got called
True
>>> te == 1
__eq__ got called
True
>>>
>>> class TestStrCmp(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __cmp__(self, other):
... print "__cmp__ got called"
... return 0
...
>>> class TestStrEq(str):
... def __new__(cls, value):
... return str.__new__(cls, value)
...
... def __eq__(self, other):
... print "__eq__ got called"
... return True
...
>>> tsc = TestStrCmp("a")
>>> tse = TestStrEq("a")
>>>
>>> "b" == tsc
False
>>> tsc == "b"
False
>>>
>>> "b" == tse
__eq__ got called
True
>>> tse == "b"
__eq__ got called
True
Edit: From Mark Dickinson's answer and comment it would appear that:
- Rich comparison overrides
__cmp__
__eq__
is it's own__rop__
to it's__op__
(and similar for__lt__
,__ge__
, etc)- If the left object is a builtin or new-style class, and the right is a subclass of it, the right object's
__rop__
is tried before the left object's__op__
This explains the behaviour in theTestStrCmp
examples. TestStrCmp
is a subclass of str
but doesn't implement its own __eq__
so the __eq__
of str
takes precedence in both cases (ie tsc == "b"
calls b.__eq__(tsc)
as an __rop__
because of rule 1).
In the TestStrEq
examples, tse.__eq__
is called in both instances because TestStrEq
is a subclass of str
and so it is called in preference.
In the TestEq
examples, TestEq
implements __eq__
and int
doesn't so __eq__
gets called both times (rule 1).
But I still don't understand the very first example with TestCmp
. tc
is not a subclass on int
so AFAICT 1.__cmp__(tc)
should be called, but isn't.
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
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
, 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.
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__
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.
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 whyy.__eq__(x)
is called in preference tox.__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?
精彩评论