为什么 `if None.__eq__("a")` 的计算结果似乎为 True(但不完全是)?
Why does `if None.__eq__("a")` seem to evaluate to True (but not quite)?
如果在 Python 3.7 中执行以下语句,它将(根据我的测试)打印 b
:
if None.__eq__("a"):
print("b")
但是,None.__eq__("a")
的计算结果为 NotImplemented
。
当然,"a".__eq__("a")
的计算结果为 True
,而 "b".__eq__("a")
的计算结果为 False
。
我最初是在测试函数的 return 值时发现这一点的,但在第二种情况下 return 什么也没发现——因此,函数 returned None
.
这是怎么回事?
这是为什么不应直接使用 __dunder__
方法的一个很好的例子,因为它们通常不是等效运算符的合适替代品;您应该使用 ==
运算符来进行相等性比较,或者在这种特殊情况下,在检查 None
时,使用 is
(跳至答案底部以获取更多信息)。
你已经完成了
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
因为被比较的类型不同。考虑另一个示例,其中以这种方式比较两个不同类型的对象,例如 1
和 'a'
。做(1).__eq__('a')
也不对,会returnNotImplemented
。比较这两个值是否相等的正确方法是
1 == 'a'
# False
这里发生的是
- 首先尝试
(1).__eq__('a')
,即returns NotImplemented
。这表示不支持该操作,所以
'a'.__eq__(1)
被调用,这也 return 相同 NotImplemented
。所以,
- 对象被视为不同,
False
被 return 编辑。
这是一个不错的小 MCVE,使用一些自定义 classes 来说明这是如何发生的:
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
当然,这并不能解释为什么操作return是正确的。这是因为 NotImplemented
实际上是一个真值:
bool(None.__eq__("a"))
# True
与
相同
bool(NotImplemented)
# True
有关哪些值被视为真值和假值的更多信息,请参阅 Truth Value Testing, as well as 上的文档部分。这里值得注意的是 NotImplemented
是真实的,但如果 class 定义了 returned 的 __bool__
或 __len__
方法,情况就会不同分别为 False
或 0
。
如果您想要 ==
运算符的等效功能,请使用 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
是一个特殊的对象,任何时候内存中只存在一个版本。 IOW,它是 NoneType
class 的唯一单例(但同一个对象可能有任意数量的引用)。 PEP8 guidelines 明确表示:
Comparisons to singletons like None
should always be done with is
or
is not
, never the equality operators.
总之,对于像 None
这样的单例,使用 is
进行参考检查更合适,尽管 ==
和 is
都可以正常工作。
您看到的结果是由于
None.__eq__("a") # evaluates to NotImplemented
计算为 NotImplemented
,NotImplemented
的真值记录为 True
:
https://docs.python.org/3/library/constants.html
Special value which should be returned by the binary special methods (e.g. __eq__()
, __lt__()
, __add__()
, __rsub__()
, etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g. __imul__()
, __iand__()
, etc.) for the same purpose. Its truth value is true.
如果您手动调用 __eq()__
方法而不是仅使用 ==
,您需要准备好应对可能 return NotImplemented
并且它的真值是真的。
如您所想,None.__eq__("a")
的计算结果为 NotImplemented
,但是如果您尝试
if NotImplemented:
print("Yes")
else:
print("No")
结果是
yes
这意味着NotImplemented
true
的真值
所以问题的结果是显而易见的:
None.__eq__(something)
产生 NotImplemented
并且 bool(NotImplemented)
的计算结果为 True
所以 if None.__eq__("a")
总是 True
为什么?
它return是一个NotImplemented
,是的:
>>> None.__eq__('a')
NotImplemented
>>>
但是如果你看这个:
>>> bool(NotImplemented)
True
>>>
NotImplemented
实际上是一个真值,所以这就是为什么它 returns b
,任何 True
都会通过,任何 False
不会。
如何解决?
你要检查一下是不是True
,所以要多点怀疑,如你所见:
>>> NotImplemented == True
False
>>>
所以你会这样做:
>>> if None.__eq__('a') == True:
print('b')
>>>
如你所见,它不会return任何东西。
如果在 Python 3.7 中执行以下语句,它将(根据我的测试)打印 b
:
if None.__eq__("a"):
print("b")
但是,None.__eq__("a")
的计算结果为 NotImplemented
。
当然,"a".__eq__("a")
的计算结果为 True
,而 "b".__eq__("a")
的计算结果为 False
。
我最初是在测试函数的 return 值时发现这一点的,但在第二种情况下 return 什么也没发现——因此,函数 returned None
.
这是怎么回事?
这是为什么不应直接使用 __dunder__
方法的一个很好的例子,因为它们通常不是等效运算符的合适替代品;您应该使用 ==
运算符来进行相等性比较,或者在这种特殊情况下,在检查 None
时,使用 is
(跳至答案底部以获取更多信息)。
你已经完成了
None.__eq__('a')
# NotImplemented
Which returns NotImplemented
因为被比较的类型不同。考虑另一个示例,其中以这种方式比较两个不同类型的对象,例如 1
和 'a'
。做(1).__eq__('a')
也不对,会returnNotImplemented
。比较这两个值是否相等的正确方法是
1 == 'a'
# False
这里发生的是
- 首先尝试
(1).__eq__('a')
,即returnsNotImplemented
。这表示不支持该操作,所以 'a'.__eq__(1)
被调用,这也 return 相同NotImplemented
。所以,- 对象被视为不同,
False
被 return 编辑。
这是一个不错的小 MCVE,使用一些自定义 classes 来说明这是如何发生的:
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
当然,这并不能解释为什么操作return是正确的。这是因为 NotImplemented
实际上是一个真值:
bool(None.__eq__("a"))
# True
与
相同bool(NotImplemented)
# True
有关哪些值被视为真值和假值的更多信息,请参阅 Truth Value Testing, as well as NotImplemented
是真实的,但如果 class 定义了 returned 的 __bool__
或 __len__
方法,情况就会不同分别为 False
或 0
。
如果您想要 ==
运算符的等效功能,请使用 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
是一个特殊的对象,任何时候内存中只存在一个版本。 IOW,它是 NoneType
class 的唯一单例(但同一个对象可能有任意数量的引用)。 PEP8 guidelines 明确表示:
Comparisons to singletons like
None
should always be done withis
oris not
, never the equality operators.
总之,对于像 None
这样的单例,使用 is
进行参考检查更合适,尽管 ==
和 is
都可以正常工作。
您看到的结果是由于
None.__eq__("a") # evaluates to NotImplemented
计算为 NotImplemented
,NotImplemented
的真值记录为 True
:
https://docs.python.org/3/library/constants.html
Special value which should be returned by the binary special methods (e.g.
__eq__()
,__lt__()
,__add__()
,__rsub__()
, etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g.__imul__()
,__iand__()
, etc.) for the same purpose. Its truth value is true.
如果您手动调用 __eq()__
方法而不是仅使用 ==
,您需要准备好应对可能 return NotImplemented
并且它的真值是真的。
如您所想,None.__eq__("a")
的计算结果为 NotImplemented
,但是如果您尝试
if NotImplemented:
print("Yes")
else:
print("No")
结果是
yes
这意味着NotImplemented
true
所以问题的结果是显而易见的:
None.__eq__(something)
产生 NotImplemented
并且 bool(NotImplemented)
的计算结果为 True
所以 if None.__eq__("a")
总是 True
为什么?
它return是一个NotImplemented
,是的:
>>> None.__eq__('a')
NotImplemented
>>>
但是如果你看这个:
>>> bool(NotImplemented)
True
>>>
NotImplemented
实际上是一个真值,所以这就是为什么它 returns b
,任何 True
都会通过,任何 False
不会。
如何解决?
你要检查一下是不是True
,所以要多点怀疑,如你所见:
>>> NotImplemented == True
False
>>>
所以你会这样做:
>>> if None.__eq__('a') == True:
print('b')
>>>
如你所见,它不会return任何东西。