如果您在Python 3.7中执行以下语句,它将(根据我的测试)打印b
:
if None.__eq__("a"):
print("b")
但是,None.__eq__("a")
的值为NotImplemented
。
自然,"a".__eq__("a")
的值为True
,而"b".__eq__("a")
的值为False
。
我最初在测试函数的返回值时发现了这一点,但在第二种情况下却未返回任何内容-因此,该函数返回了None
。
这是怎么回事?
答案 0 :(得分:172)
这是一个很好的例子,说明为什么不应该直接使用__dunder__
方法,因为它们通常不是等效运算符的适当替代;您应该使用==
运算符代替相等比较,或者在这种特殊情况下,当检查None
时,请使用is
(跳至答案底部以获取更多信息)。
您已经完成
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和this answer上的“文档”部分。这里值得注意的是NotImplemented
是真实的,但是如果类定义了返回__bool__
或{{1的__len__
或False
方法,那将是另一回事}}。
如果要使用与0
运算符等效的功能,请使用operator.eq
:
==
但是,如前所述,对于此特定方案,您要在其中检查import operator
operator.eq(1, 'a')
# False
,请使用None
:
is
等效的功能是使用operator.is_
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
operator.is_(var2, None)
# True
是一个特殊的对象,并且在任何时间点内存中只有1个版本。 IOW,它是None
类的唯一单例(但是同一对象可以具有任意数量的引用)。 PEP8 guidelines明确说明了这一点:
与
NoneType
之类的单例进行比较时,应始终使用None
或is
,永远不要等于运算符。
总而言之,对于is not
之类的单例来说,使用None
进行参考检查更为合适,尽管is
和==
都可以正常工作。
答案 1 :(得分:33)
您看到的结果是由于以下事实造成的:
None.__eq__("a") # evaluates to NotImplemented
求值为NotImplemented
,并且NotImplemented
的真实值记录为True
:
https://docs.python.org/3/library/constants.html
应该由二进制特殊方法(例如
__eq__()
,__lt__()
,__add__()
,__rsub__()
等)返回的特殊值,以指示该操作不是关于另一种类型实施;出于同一目的,可以通过就地二进制特殊方法(例如__imul__()
,__iand__()
等)返回。 其真实值是真实的。
如果您手动调用__eq()__
方法而不是仅使用==
,则需要准备好处理它可能返回NotImplemented
并且其真值是true的可能性。
答案 2 :(得分:16)
您已经知道None.__eq__("a")
的取值为NotImplemented
,但是,如果您尝试类似的操作
if NotImplemented:
print("Yes")
else:
print("No")
结果是
是
这意味着NotImplemented
true
因此,问题的结果显而易见:
None.__eq__(something)
产生NotImplemented
bool(NotImplemented)
的值为True
所以if None.__eq__("a")
始终为真
答案 3 :(得分:1)
它返回NotImplemented
,是的:
>>> None.__eq__('a')
NotImplemented
>>>
但是,如果您看这个:
>>> bool(NotImplemented)
True
>>>
NotImplemented
实际上是一个真实的值,所以这就是它返回b
的原因,True
的任何内容都会通过,False
的任何内容都不会通过。>
您必须检查它是否为True
,因此请更加怀疑,如您所见:
>>> NotImplemented == True
False
>>>
所以您会这样做:
>>> if None.__eq__('a') == True:
print('b')
>>>
如您所见,它不会返回任何内容。