如果您在Python 3.7中执行以下语句,则会(根据我的测试)打印b
:
if None.__eq__("a"):
print("b")
然而,None.__eq__("a")
的结果是NotImplemented
。
显然,"a".__eq__("a")
的结果是True
,"b".__eq__("a")
的结果是False
。
我最初在测试函数的返回值时发现这一点,在第二种情况下没有返回任何东西——因此,该函数返回了None
。
这里到底发生了什么?
如果您在Python 3.7中执行以下语句,则会(根据我的测试)打印b
:
if None.__eq__("a"):
print("b")
然而,None.__eq__("a")
的结果是NotImplemented
。
显然,"a".__eq__("a")
的结果是True
,"b".__eq__("a")
的结果是False
。
我最初在测试函数的返回值时发现这一点,在第二种情况下没有返回任何东西——因此,该函数返回了None
。
这里到底发生了什么?
None.__eq__('a')
# NotImplemented
由于正在比较的类型不同,因此返回NotImplemented
。再考虑另一个例子,以类似的方式比较两个具有不同类型的对象,例如1
和'a'
。执行(1).__eq__('a')
也是不正确的,并且会返回NotImplemented
。比较这两个值是否相等的正确方法应该是:
1 == 'a'
# False
这里发生的情况是:
(1).__eq__('a')
,返回NotImplemented
。这表明不支持该操作,因此'a'.__eq__(1)
,也返回相同的NotImplemented
。所以,False
。这里有一个漂亮的小MCVE,使用一些自定义类来说明这是如何发生的:
class A:
def __eq__(self, other):
print('A.__eq__')
return NotImplemented
class B:
def __eq__(self, other):
print('B.__eq__')
return NotImplemented
class C:
def __eq__(self, other):
print('C.__eq__')
return True
a = A()
b = B()
c = C()
print(a == b)
# A.__eq__
# B.__eq__
# False
print(a == c)
# A.__eq__
# C.__eq__
# True
print(c == a)
# C.__eq__
# True
当然,这并不能解释为什么该操作返回true。这是因为NotImplemented
实际上是一个真值:
bool(None.__eq__("a"))
# True
同上,
bool(NotImplemented)
# True
要了解哪些值被视为真和假,请参见文档中关于Truth Value Testing的部分,以及此回答。需要注意的是,NotImplemented
是真值,但如果该类定义了返回False
或0
的__bool__
或__len__
方法,情况就会不同。
如果你想使用功能等同于==
运算符的,使用operator.eq
:
import operator
operator.eq(1, 'a')
# False
然而,正如早些时候提到的那样,对于 此特定情况,在检查 None
时,请使用 is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
相当于这个的功能是使用 operator.is_
:
operator.is_(var2, None)
# True
None
是一个特殊对象,在任何时候只有一个版本存在于内存中。也就是说,它是NoneType
类的唯一单例(但同一个对象可能具有任意数量的引用)。 PEP8指南 明确说明了这一点:
对于像
None
这样的单例,应始终使用is
或is not
进行比较,而不是相等运算符。
总之,对于像None
这样的单例,使用is
进行引用检查更为合适,虽然==
和is
都可以正常工作。
你看到的结果是由于这个事实引起的
None.__eq__("a") # evaluates to NotImplemented
评估为NotImplemented
,并且已经记录了NotImplemented
的真值是True
:
https://docs.python.org/3/library/constants.html
特殊值,应由二进制特殊方法(例如
__eq__(),__lt__(),__add__(),__rsub__()等)返回,表示该操作未针对其他类型实现; 可以由就地二进制特殊方法(例如
__imul__(),__iand__()等)返回相同的目的。它的真值为true。
如果您手动调用__eq()__
方法而不仅仅使用==
,则需要准备好处理它可能会返回NotImplemented
并且其真值为true的可能性。
正如你已经发现的那样,None.__eq__("a")
的求值结果为 NotImplemented
,但如果你尝试类似下面的东西
if NotImplemented:
print("Yes")
else:
print("No")
结果是
是的
这意味着 NotImplemented
的真值为 true
因此问题的结果是显而易见的:
None.__eq__(something)
返回 NotImplemented
bool(NotImplemented)
的值为 True
所以如果 None.__eq__("a")
始终为True
它会返回一个 NotImplemented
,是的:
>>> None.__eq__('a')
NotImplemented
>>>
但是如果你看这个:
>>> bool(NotImplemented)
True
>>>
NotImplemented
实际上是一个真值,这就是为什么它返回b
,任何True
的东西都会通过,任何False
的东西都不会通过。
你必须检查它是否为True
,所以要更加怀疑,就像你看到的:
>>> NotImplemented == True
False
>>>
So you would do:
>>> if None.__eq__('a') == True:
print('b')
>>>