为什么/何时在 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==ycalls 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 theTestStrCmpexamples. TestStrCmpis a subclass of strbut doesn't implement its own __eq__so the __eq__of strtakes 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 TestStrEqexamples, tse.__eq__is called in both instances because TestStrEqis a subclass of strand so it is called in preference.
在TestStrEq示例中,tse.__eq__在两个实例中都被调用,因为它TestStrEq是 的子类,str因此优先调用它。
In the TestEqexamples, TestEqimplements __eq__and intdoesn'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. tcis not a subclass on intso 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
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, 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.
对于对象
xandy,首先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 NotImplementedin 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" == tscand 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 NotImplementedand 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__()“丰富的比较”方法。

