为什么`如果没有.__ eq __("a")`评估为真?

The*_*ect 145 python string boolean-expression equivalence python-3.x

如果你在Python 3.7中执行以下语句,它将(从我的测试)打印b:

if None.__eq__("a"):
    print("b")
Run Code Online (Sandbox Code Playgroud)

但是,None.__eq__("a")评估为NotImplemented.

当然,"a".__eq__("a")评估True"b".__eq__("a")评估False.

我最初在测试函数的返回值时发现了这个,但在第二种情况下没有返回任何内容 - 因此,函数返回了None.

这里发生了什么?

cs9*_*s95 176

这是为什么__dunder__不应该直接使用这些方法的一个很好的例子,因为它们通常不适合替代它们的等效运算符; 您应该使用==运算符进行相等比较,或者在此特殊情况下,在检查时None使用is(跳到答案的底部以获取更多信息).

你做完了

None.__eq__('a')
# NotImplemented
Run Code Online (Sandbox Code Playgroud)

NotImplemented由于被比较的类型不同,因此返回.考虑另一个例子,其中以这种方式比较具有不同类型的两个对象,例如1'a'.做(1).__eq__('a')也不正确,并将返回NotImplemented.将这两个值进行比较的正确方法是

1 == 'a'
# False
Run Code Online (Sandbox Code Playgroud)

这里发生的是

  1. 首先,(1).__eq__('a')尝试,返回NotImplemented.这表示不支持该操作,因此
  2. 'a'.__eq__(1)被调用,也返回相同NotImplemented.所以,
  3. 对象被视为不相同,并被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
Run Code Online (Sandbox Code Playgroud)

当然,这并不能解释为什么操作返回true.这是因为NotImplemented实际上是一个真正的价值:

bool(None.__eq__("a"))
# True
Run Code Online (Sandbox Code Playgroud)

与...一样,

bool(NotImplemented)
# True
Run Code Online (Sandbox Code Playgroud)

有关哪些值被视为真实和虚假的更多信息,请参阅真值测试的文档部分以及此答案.值得注意的是,这里NotImplemented是truthy,但它会是一个不同的故事有类中定义的__bool____len__该方法返回的False0分别.


如果您想要与==运算符等效的功能,请使用operator.eq:

import operator
operator.eq(1, 'a')
# False
Run Code Online (Sandbox Code Playgroud)

但是,如前所述,对于您要检查的特定方案,请None使用is:

var = 'a'
var is None
# False

var2 = None
var2 is None
# True
Run Code Online (Sandbox Code Playgroud)

功能等同于使用operator.is_:

operator.is_(var2, None)
# True
Run Code Online (Sandbox Code Playgroud)

None是一个特殊的对象,任何时候内存中只有1个版本.IOW,它是NoneType该类的唯一单例(但同一个对象可能有任意数量的引用).该PEP8方针更加明确:

与单身人士的比较None应始终使用is或者 is not从不使用相等运算符.

总之,对于喜欢单身None,与基准检查is是比较合适的,虽然两者==is会工作得很好.


Mar*_*yer 33

你看到的结果是由那个事实引起的

None.__eq__("a") # evaluates to NotImplemented
Run Code Online (Sandbox Code Playgroud)

评估为NotImplemented,并将NotImplemented真实值记录为True:

https://docs.python.org/3/library/constants.html

二进制特殊方法应返回的特殊值(例如eq(),lt(),add(),rsub()等),表示该操作未针对其他类型实现; 可以由就地二进制特殊方法(例如imul(),iand()等)返回,用于相同的目的.它的真实价值是真实的.

如果您__eq__()手动调用方法而不是仅使用__lt__(),则需要准备好处理它可能返回的可能性__add__()以及其真值是真的.


Kan*_*jiu 16

正如你已经想通None.__eq__("a")计算结果为NotImplemented但是如果你尝试类似

if NotImplemented:
    print("Yes")
else:
    print("No")
Run Code Online (Sandbox Code Playgroud)

结果是

这意味着真相的价值 NotImplemented true

因此,问题的结果是显而易见的:

None.__eq__(something) 产量 NotImplemented

bool(NotImplemented)评估为True

if None.__eq__("a")总是如此