为什么/何时在 Python 中`x==y` 调用`y.__eq__(x)`?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2281222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why/When in Python does `x==y` call `y.__eq__(x)`?
提问by Singletoned
The Python docs clearly state that x==y
calls x.__eq__(y)
. However it seems that under many circumstances, the opposite is true. Where 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.
Python 文档清楚地说明x==y
调用x.__eq__(y)
. 然而,似乎在许多情况下,情况恰恰相反。它在哪里记录何时或为什么发生这种情况,以及我如何确定我的对象__cmp__
或__eq__
方法是否会被调用。
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.
编辑:只是为了澄清,我知道__eq__
在 preferredecne to 中调用__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
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__
- 丰富的比较覆盖
__cmp__
__eq__
是它自己的__rop__
,以它的__op__
(以及类似的__lt__
,__ge__
等等)- 如果左对象是内置类或新式类,而右对象
__rop__
是它的子类,则在左对象之前尝试右对象__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).
这解释了TestStrCmp
示例中的行为。 TestStrCmp
是 of 的子类,str
但不实现自己的,__eq__
因此在这两种情况下__eq__
ofstr
优先(即,由于规则 1tsc == "b"
调用b.__eq__(tsc)
为 an __rop__
)。
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.
在TestStrEq
示例中,tse.__eq__
在两个实例中都被调用,因为它TestStrEq
是 的子类,str
因此优先调用它。
In the TestEq
examples, TestEq
implements __eq__
and int
doesn't so __eq__
gets called both times (rule 1).
在TestEq
示例中,TestEq
实现__eq__
和int
没有__eq__
被两次调用(规则 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.
但我仍然不明白第一个带有TestCmp
. tc
不是子类,int
所以 AFAICT1.__cmp__(tc)
应该被调用,但不是。
采纳答案by Mark Dickinson
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
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.
对于对象
x
andy
,首先x.__op__(y)
尝试。如果这没有实现或返回NotImplemented
,y.__rop__(x)
则尝试。如果这也未实现或返回NotImplemented
,则会引发 TypeError 异常。但看到以下异常:上一项的例外:如果左操作数是内置类型或新式类的实例,而右操作数是该类型或类的适当子类的实例并覆盖基类的
__rop__()
方法,则右操作数操作的__rop__()
方法是左操作的尝试过__op__()
的方法。
回答by Dancrumb
Actually, in the docs, it states:
实际上,在文档中,它指出:
[
__cmp__
is c]alled by comparison operations if rich comparison (see above) is not defined.
__cmp__
如果未定义丰富的比较(见上文),则[由比较操作调用。
__eq__
is a rich comparison method and, in the case of TestCmp
, is not defined, hence the calling of __cmp__
__eq__
是一种丰富的比较方法,在 的情况下TestCmp
,未定义,因此调用__cmp__
回答by dubiousjim
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.
这在语言参考中没有记录吗?只是从那里快速看一下,__cmp__
当, 等被定义时__eq__
,它看起来像是被忽略了__lt__
。我理解包括在__eq__
父类上定义的情况。str.__eq__
已定义,因此__cmp__
其子类将被忽略。object.__eq__
等没有定义,所以__cmp__
它的子类将被尊重。
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.
我知道这
__eq__
在 preferredecne to中被调用__cmp__
,但我不清楚为什么y.__eq__(x)
优先于 调用x.__eq__(y)
,当后者是文档状态时会发生的情况。
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.
文档说x.__eq__(y)
将首先被调用,但它可以选择NotImplemented
在y.__eq__(x)
调用的情况下返回。我不知道为什么你有信心这里正在发生一些不同的事情。
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.
您对哪种情况特别感到困惑?我理解你只是被迷惑关于"b" == tsc
和tsc == "b"
的情况下,是否正确?在任何一种情况下,str.__eq__(onething, otherthing)
都被调用。由于您没有覆盖__eq__
TestStrCmp 中的方法,因此最终您只是依赖于基本字符串方法,并且它说对象不相等。
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.
在不知道 的实现细节的情况下str.__eq__
,不知道是否("b").__eq__(tsc)
会返回NotImplemented
并给 tsc 一个处理相等测试的机会。但即使这样做了,按照您定义 TestStrCmp 的方式,您仍然会得到错误的结果。
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 eitherof 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?
也许有什么情况是,Python是宁愿__eq__
到__cmp__
,如果它定义任何对象进行比较,而您所期望__cmp__
的最左边的对象转移到优先__eq__
右手边的对象上。是这样吗?
回答by Mikhail Churbanov
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.
据我所知,__eq__()
是一种所谓的“丰富比较”方法,优先于__cmp__()
下面调用比较运算符。__cmp__()
如果未定义“丰富比较”,则调用。
So in A == B:
If __eq__()
is defined in A it will be called
Else __cmp__()
will be called
所以在 A == B 中:
如果__eq__()
在 A 中定义它将被称为
否则__cmp__()
将被调用
__eq__()
defined in 'str' so your __cmp__()
function was not called.
__eq__()
在 'str' 中定义,所以你的__cmp__()
函数没有被调用。
The same rule is for __ne__(), __gt__(), __ge__(), __lt__()
and __le__()
"rich comparison" methods.
相同的规则适用于__ne__(), __gt__(), __ge__(), __lt__()
和__le__()
“丰富的比较”方法。