Lau*_*RTE 11 python operators python-2.7
我正在玩__eq__操作员和NotImplemented价值.
我试图了解obj1.__eq__(obj2)返回时会发生什么NotImplemented,obj2.__eq__(obj1)也会返回NotImplemented.
根据为什么返回NotImplemented而不是引发NotImplementedError的答案,以及详细的文章如何在"LiveJournal"博客中覆盖Python中的比较运算符,运行时应该回归到内置行为(基于身份==和!=).
但是,尝试下面的示例,似乎我__eq__对每对对象都有多个调用.
class Apple(object):
def __init__(self, color):
self.color = color
def __repr__(self):
return "<Apple color='{color}'>".format(color=self.color)
def __eq__(self, other):
if isinstance(other, Apple):
print("{self} == {other} -> OK".format(self=self, other=other))
return self.color == other.color
print("{self} == {other} -> NotImplemented".format(self=self, other=other))
return NotImplemented
class Orange(object):
def __init__(self, usage):
self.usage = usage
def __repr__(self):
return "<Orange usage='{usage}'>".format(usage=self.usage)
def __eq__(self, other):
if isinstance(other, Orange):
print("{self} == {other}".format(self=self, other=other))
return self.usage == other.usage
print("{self} == {other} -> NotImplemented".format(self=self, other=other))
return NotImplemented
>>> apple = Apple("red")
>>> orange = Orange("juice")
>>> apple == orange
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
False
Run Code Online (Sandbox Code Playgroud)
我希望只有:
<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented
Run Code Online (Sandbox Code Playgroud)
然后回到身份比较id(apple) == id(orange)- > False.
这是Python跟踪器中的问题#6970 ; 它在2.7和Python 3.0和3.1中保持不变.
这是由两个地方同时尝试直接和交换比较引起的,当__eq__执行两个自定义类与方法之间的比较时.
丰富的比较通过该PyObject_RichCompare()函数,对于具有不同类型(间接)委托的对象try_rich_compare().在这个函数中v,它w是左右操作数对象,并且由于两者都有一个__eq__方法,因此函数调用v->ob_type->tp_richcompare()和w->ob_type->tp_richcompare().
对于自定义类,tp_richcompare()槽被定义为slot_tp_richcompare()函数,并且此函数再次__eq__针对双方执行,self.__eq__(self, other)然后再执行other.__eq__(other, self).
最后,这意味着apple.__eq__(apple, orange)并且orange.__eq__(orange, apple)被调用第一次尝试try_rich_compare(),然后调用反向,导致orange.__eq__(orange, apple)和apple.__eq__(apple, orange)调用self和other交换slot_tp_richcompare().
请注意,问题仅限于两个类定义__eq__方法的不同自定义类的实例.如果任何一方没有这样的方法__eq__只执行一次:
>>> class Pear(object):
... def __init__(self, purpose):
... self.purpose = purpose
... def __repr__(self):
... return "<Pear purpose='{purpose}'>".format(purpose=self.purpose)
...
>>> pear = Pear("cooking")
>>> apple == pear
<Apple color='red'> == <Pear purpose='cooking'> -> NotImplemented
False
>>> pear == apple
<Apple color='red'> == <Pear purpose='cooking'> -> NotImplemented
False
Run Code Online (Sandbox Code Playgroud)
如果你有两个相同类型和__eq__返回的实例NotImplemented,你甚至可以得到六个比较:
>>> class Kumquat(object):
... def __init__(self, variety):
... self.variety = variety
... def __repr__(self):
... return "<Kumquat variety=='{variety}'>".format(variety=self.variety)
... def __eq__(self, other):
... # Kumquats are a weird fruit, they don't want to be compared with anything
... print("{self} == {other} -> NotImplemented".format(self=self, other=other))
... return NotImplemented
...
>>> Kumquat('round') == Kumquat('oval')
<Kumquat variety=='round'> == <Kumquat variety=='oval'> -> NotImplemented
<Kumquat variety=='oval'> == <Kumquat variety=='round'> -> NotImplemented
<Kumquat variety=='round'> == <Kumquat variety=='oval'> -> NotImplemented
<Kumquat variety=='oval'> == <Kumquat variety=='round'> -> NotImplemented
<Kumquat variety=='oval'> == <Kumquat variety=='round'> -> NotImplemented
<Kumquat variety=='round'> == <Kumquat variety=='oval'> -> NotImplemented
False
Run Code Online (Sandbox Code Playgroud)
第一组两次比较是从优化尝试中调出来的; 当两个实例具有相同的类型时,您只需要调用v->tp_richcompare(v, w)并且可以跳过强制(对于数字).但是,当该比较失败(NotImplemented返回)时,也会尝试标准路径.
如何在Python 2中进行比较变得相当复杂,因为__cmp__仍需要支持旧的3向比较方法; 在Python 3中,支持__cmp__删除,更容易解决问题.因此,修复程序从未向后移植到2.7.