x==y
会调用x.__eq__(y)
,但是在许多情况下,相反的情况似乎是正确的。在什么时候或为什么发生这种情况以及如何确定我的对象的__cmp__
或__eq__
方法将被调用有没有文档记录。编辑:仅想澄清一点,我知道
__eq__
比__cmp__
更优先调用,但我不清楚为什么首选y.__eq__(x)
而不是x.__eq__(y)
,后者是文档中所述的发生的事情。>>> 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
编辑:根据Mark Dickinson的回答和评论,似乎:
- 丰富比较重载了
__cmp__
__eq__
是其自己的__rop__
(类似于__lt__
,__ge__
等等)- 如果左侧对象是内置或新式类,并且右侧对象是它的子类,则在调用左侧对象的
__op__
之前,将尝试右侧对象的__rop__
这解释了TestStrCmp
示例中的行为。 TestStrCmp
是str
的子类,但没有实现自己的__eq__
,因此在两种情况下都优先调用str
的__eq__
(即tsc == "b"
因为规则1而调用b.__eq__(tsc)
作为一个__rop__
)。
在TestStrEq
示例中,在两个实例中都调用tse.__eq__
,因为TestStrEq
是str
的子类,所以它被优先调用。
在TestEq
示例中,TestEq
实现了__eq__
而int
没有,因此__eq__
被连续调用两次(规则1)。
但是我仍然不理解TestCmp
的第一个示例。 tc
不是int
的子类,因此根据我的理解应该调用1.__cmp__(tc)
,但没有。
__rop__
方法。比较方法在这方面是特殊的:__eq__
是其自身的反向方法,因此对于__op__
和__rop__
都应该阅读__eq__
。(类似地,__ne__
是其自身的反向方法,__le__
是__ge__
的反向方法等等。)其他人之前也评论过(我认为正确),文档在这方面需要进行一些完善。我几乎可以确定__rop__
方法并未被弃用! - Mark Dickinson__lt__()
和__gt__()
互为镜像,__le__()
和__ge__()
互为镜像,而__eq__()
和__ne__()
则是它们自己的镜像。”或者你是在询问__ror__
方法不会被弃用的证据? - Mark Dickinson(2<2)==(not(2>=2))
。 - Singletoned__lt__
是__gt__
的__rop__
。这里没有进行逻辑否定;只是对参数进行了反转。翻译如下:x.__lt__(y)
<=>x < y
<=>y > x
<=>y.__gt__(x)
。 - Mark Dickinson__cmp__
(尤其是与丰富比较结合的情况)的规则非常复杂,我认为它们甚至没有被适当地记录在任何地方,除了源代码。如果你感兴趣的话,(可以)在 Objects/object.c 文件中的 PyObject_RichCompare 中查找。在1 == tc
示例中,两侧都没有实现__eq__
,因此我们回退到__cmp__
。int.__cmp__
只能处理与其他整数的比较,所以它会被忽略(甚至不会被调用),而是调用你的TestCmp.__cmp__
方法。在 py3k 中消除__cmp__
是一件非常好的事情。 :) - Mark Dickinson