我参加了我的第一个计算科学课程,我们刚刚学习了类实现和继承。特别是,我们刚刚介绍了方法覆盖以及我们定义的类如何默认继承自object
超类。作为我尝试这种特殊继承情况的一个例子,我使用了以下代码:
class A:
def __init__(self, i):
self.i = i
def __str__(self):
return "A"
# Commenting out these two lines to not override __eq__(), just use the
# default from our superclass, object
#def __eq__(self, other):
#return self.i == other.i
x = A(2)
y = A(2)
>>>print(x == y)
False
>>>print(x.__eq__(y))
NotImplemented
我期待(x == y)
的结果,因为根据我的理解,__eq__()
的默认设置是检查它们是否是相同的对象,而不是担心内容。哪个是False
,x
和y
具有相同的内容,但却是不同的对象。第二个让我感到惊讶。
所以我的问题:我认为(x==y)
和x.__eq__(y)
是同义词并且完全相同。为什么这些会产生不同的输出?为什么第二个条件返回NotImplemented
?
答案 0 :(得分:9)
==
运算符等效于eq
函数,如果存在,则会在内部调用左操作数的__eq__
方法以尝试确定相等性。这不是唯一的事情,如果__eq__
不存在,就像这里的情况一样,它会做其他检查,例如检查两者是否是同一个对象,或__cmp__
pre-Python 3。
简而言之,您的混淆源于这种假设,这是不正确的:
我认为(x == y)和x .__ eq __(y)是同义词并且完全相同的呼叫
事实上,(x==y)
和operators.eq(x, y)
是同义词,x.__eq__(y)
是eq(x, y)
尝试检查的内容之一。
答案 1 :(得分:6)
您从继承的__eq__
方法返回的NotImplemented
value是一个特殊的内置值,在Python中用作哨兵。它可以由实现数学运算符或比较运算符的__magic__
方法返回,以指示该类不支持尝试的运算符(使用提供的参数)。
这比引发异常更有用,因为它允许Python回退到其他选项来解决操作符的使用。例如,如果你执行x + y
,Python将首先尝试运行x.__add__(y)
。如果返回NotImplemented
,则接下来会尝试"反向"版本y.__radd__(x)
,如果y
是比x
更复杂的类型,则可能有效。
如果您要询问x == y
,则Python首先尝试x.__eq__(y)
,然后y.__eq__(x)
,最后x is y
(最终将评估为布尔值)。由于object.__eq__
在所有情况下均返回NotImplemented
,因此当您使用真实运算符时,您的类会回退到身份比较,但在您直接调用NotImplemented
时会向您显示__eq__
标记
答案 2 :(得分:0)
如果您已为某个类实现了__eq__()
函数,则在使用x == y
时会调用它。否则x == y
依赖于默认比较逻辑。定义类时,__eq__()
不会自动实现。