样式指南中写道。
# Correct:
if greeting:
# Wrong:
if greeting == True:
# Worse:
if greeting is True:
看 PEP 8,搜索 "更糟 "这个词
为什么会这样呢?我习惯于尽可能明确地检查条件,以使代码更易读,并捕捉异常情况。
考虑一下这个函数。
def f(do_it):
if do_it : print("doit")
else : print("no don't")
它很容易被滥用 监督,与意想不到的行为。
>>> f("False")
doit
>>> f([False])
doit
例如,当你在检查一个可能无意中传递if子句的返回值时,这是一个真正的问题。这可以通过使用 is
构。
显然,PEP的建议有一个很好的理由,但它是什么呢?
在评论者的提示下,进一步的研究使我有了以下发现。
if x:
调用x类的__bool方法 该方法应该返回True或False 取决于对象认为自己是哪一个.
if x==True:
调用 x 类的 __eq 方法,该方法应该能够将自己与 True(或 False)进行比较,并根据情况返回 True 或 False。
if x is True
既不调用。这将测试 x 是否是 "True "对象。它完全规避了 __eq 和 __bool 方法。
注意:我不是在问关于 ==
和 is
. 如果这就是你来这里的原因,请看一下。"=="和 "is "有区别吗?
从理论层面来说。is
表达了错误的东西。我们关心的是价值的真实性,而不是身份。在极少数情况下,我们关心的是身份,而不是价值的真实性。is
比较合适。
从实践层面看。is True
甚至不工作的方式 人们期望它。
In [1]: import numpy
In [2]: x = numpy.array([1, 2, 3])
In [3]: flag = x[0] == 1
In [4]: flag
Out[4]: True
In [5]: if flag: print('true')
true
In [6]: if flag is True: print('true')
In [7]:
我们把1和1进行比较,得到的东西看起来像是 True
但是 is
比较失败。那是因为 bool
并不是唯一的布尔类型。库可以自由定义自己的类型。flag
的一个实例。numpy.bool_
,它是一个不同的对象 True
. (NumPy这样做有一个很好的理由--使用他们自己的布尔类型可以让他们对0维值的处理更加统一。这也是NumPy也有自己的数值标量类型的原因)。)
另外。is True
甚至在你的例子中都没有发现问题。它只是把一个沉默的错误行为换成了另一个。f("False")
打印 doit
是个问题,但也是 f("True")
默默地什么都不做。两个版本的测试都没有产生实际的错误信息。
为什么会这样呢?
因为它在逻辑上是错误的,一个 类别错误. 随着 is
你明确地执行了一个身份检查,一个参考比较。但这不是你 打算 在这里做。的 意图 的代码是为了检查一个值是否为真值(或者,更严格的说。True
). 该值是否与常量 True
不仅是无关紧要的,而且是主动分散注意力的。
换句话说,该守则的意图是涉及到 价值 的表达方式,所以检查其 价值,而不是其 参考身份.