Python 为什么“如果没有.”eq“a”看起来是正确的(但不是完全正确的)?
如果在Python 3.7中执行以下语句,它将(根据我的测试)打印Python 为什么“如果没有.”eq“a”看起来是正确的(但不是完全正确的)?,python,python-3.x,string,boolean-expression,equivalence,Python,Python 3.x,String,Boolean Expression,Equivalence,如果在Python 3.7中执行以下语句,它将(根据我的测试)打印b: if None.__eq__("a"): print("b") 但是,None.\uuuu eq\uuu(“a”)的计算结果为NotImplemented 自然地,“a”和“a”的计算结果分别为True和“b”。“a”和的计算结果分别为False和 我最初在测试函数的返回值时发现了这一点,但在第二种情况下没有返回任何内容——因此,函数返回了None 这里发生了什么?这是一个很好的例子,说明了为什么不应该直接使用\u
b
:
if None.__eq__("a"):
print("b")
但是,None.\uuuu eq\uuu(“a”)
的计算结果为NotImplemented
自然地,“a”和“a”的计算结果分别为True和“b”。“a”和的计算结果分别为False和
我最初在测试函数的返回值时发现了这一点,但在第二种情况下没有返回任何内容——因此,函数返回了None
这里发生了什么?这是一个很好的例子,说明了为什么不应该直接使用\uu dunder\uuu
方法,因为它们通常不适合替换其等效运算符;您应该使用==
运算符进行相等比较,或者在这种特殊情况下,在检查无
时,使用is
(有关详细信息,请跳到答案的底部)
你完成了
None.__eq__('a')
# NotImplemented
由于所比较的类型不同,因此返回NotImplemented
。请考虑另一个示例,其中两种不同类型的对象正在以这种方式进行比较,例如<代码> 1 和<代码>“A”/代码>。执行(1)。\uuuu eq\uuuu('a')
也不正确,将返回未执行
。比较这两个值是否相等的正确方法是
1 == 'a'
# False
这里发生的是
首先,(1)。\uuuu eq\uuuu('a')
被尝试,它返回未实现
。这表示不支持该操作,因此
'a.\uuuu eq\uuuu(1)
被调用,它还返回相同的未实现的。所以
对象被视为不相同,并返回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
有关哪些值被视为truthy和falsy的更多信息,请参阅上的文档部分,以及。这里值得注意的是,NotImplemented
是真实的,但是如果类分别定义了返回False
或0
的或len
方法,情况就不同了
如果需要与=
运算符等效的功能,请使用:
但是,如前所述,对于此特定场景,如果要检查None
,请使用is
:
var = 'a'
var is None
# False
var2 = None
var2 is None
# True
其功能等效于使用:
None
是一个特殊的对象,在任何时候内存中只存在一个版本。照此,它是NoneType
类的唯一单例(但同一个对象可以有任意数量的引用)。委员会明确指出:
与诸如None
之类的单例进行比较时,应始终使用is
或
不是
,决不是相等运算符
总之,对于像None
这样的单例,使用is
进行参考检查更合适,尽管=
和is
都可以正常工作。您看到的结果是由以下事实造成的:
None.__eq__("a") # evaluates to NotImplemented
计算结果为NotImplemented
,并且NotImplemented
的真值记录为True
:
应通过二进制特殊方法返回的特殊值(例如,\uuuuu eq\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()
,,\uuuuuuuuuuuuuuuuuuuuuuuuu;可通过就地二进制特殊方法返回(例如,\uu imul\uu()
,\uuu iand\uuu()
等),用于相同目的其真值为真。
如果手动调用\uuu eq()\uuuu
方法,而不是仅使用=
,则需要准备好处理它可能返回NotImplemented
且其真值为真的可能性 正如您已经计算出的无。
的计算结果为未实现
if NotImplemented:
print("Yes")
else:
print("No")
结果是
对
这意味着NotImplemented
true
因此,问题的结果是显而易见的:
None.\uuuu eq\uuuu(某物)
产生NotImplemented
而bool(未实现)
的计算结果为True
所以,如果没有,那么。\uuuueq\uuuu(“a”)
总是正确的为什么?
它返回一个未实现的,耶:
>>> None.__eq__('a')
NotImplemented
>>>
但如果你看看这个:
>>> bool(NotImplemented)
True
>>>
NotImplemented
实际上是一个真实值,因此它返回b
,任何True
都将通过,任何False
都不会通过
如何解决?
您必须检查它是否为真
,因此请更加怀疑,如您所见:
>>> NotImplemented == True
False
>>>
所以你会这样做:
>>> if None.__eq__('a') == True:
print('b')
>>>
正如你所看到的,它不会返回任何东西。最直观的答案-值得添加-谢谢:)“值得添加”并没有完全抓住我想说的话(正如你所看到的)-也许“迟来的卓越”是我想要的-cheers@scharfmn对我很想知道你认为这个答案增加了哪些以前没有涉及过的内容。不知何故,这里的视觉/回复功能增加了清晰度-完整性demo@scharfmn ... 虽然提示已被删除,但已接受的答案也已被删除。您是否仅仅因为终端提示被懒散地保留在屏幕上而进行了投票?
>>> NotImplemented == True
False
>>>
>>> if None.__eq__('a') == True:
print('b')
>>>