gpt4 book ai didi

python - 为什么使用 __eq__ 运算符多次评估 NotImplemented

转载 作者:太空狗 更新时间:2023-10-29 18:07:03 26 4
gpt4 key购买 nike

不要把苹果和橙子混在一起

问题

我正在使用 __eq__ 运算符和 NotImplemented 值。

我试图了解当 obj1.__eq__(obj2) 返回 NotImplemented 并且 obj2.__eq__(obj1) 也返回时会发生什么未实现

根据的回答Why return NotImplemented instead of raising NotImplementedError ,以及详细文章 How to override comparison operators in Python 在“LiveJournal”博客中,运行时应该回退到内置行为(基于 ==!= 的标识)。

代码示例

但是,尝试下面的示例,我似乎为每对对象多次调用了 __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

预期行为

我预计只有:

<Apple color='red'> == <Orange usage='juice'> -> NotImplemented
<Orange usage='juice'> == <Apple color='red'> -> NotImplemented

然后回到身份比较 id(apple) == id(orange) -> False

最佳答案

这是 issue #6970在 Python 跟踪器中;它在 2.7 和 Python 3.0 和 3.1 中仍未修复。

这是由于在使用 __eq__ 方法执行两个自定义类之间的比较时,两个地方尝试直接比较和交换比较引起的。

通过 PyObject_RichCompare() function 进行丰富的比较,对于不同类型的对象(间接)委托(delegate)给 try_rich_compare() .在这个函数中,vw 是左右操作数对象,因为它们都有一个 __eq__ 方法,所以函数同时调用了 v ->ob_type->tp_richcompare()w->ob_type->tp_richcompare()

对于自定义类,tp_richcompare() slot被定义为 slot_tp_richcompare() function ,并且此函数再次为双方执行__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) 调用因为 selfotherslot_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

如果您有两个相同类型的实例并且__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

第一组两个比较是从优化尝试中调用的;当两个实例具有相同的类型时,您只需要调用 v->tp_richcompare(v, w) 并且可以跳过强制转换(对于数字),毕竟。但是,当比较失败时(返回 NotImplemented),则尝试了标准路径。

在 Python 2 中如何进行比较变得相当复杂,因为仍然必须支持旧的 __cmp__ 3 向比较方法;在 Python 3 中,随着对 __cmp__ 的支持被删除,更容易解决这个问题。因此,此修复程序从未向后移植到 2.7。

关于python - 为什么使用 __eq__ 运算符多次评估 NotImplemented,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39558377/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com