关于比较布尔值与True或False的奇怪PEP8建议
在我阅读Python的PEP 8时,最后提到:
不要用
==
来比较布尔值是否为 True 或 FalseYes: if greeting: No: if greeting == True: Worse: if greeting is True:
当布尔值是 True
时,我觉得这个建议没问题,但当我想检查是否为 False
时,这听起来就有点奇怪了。
如果我想知道一个变量 greeting 是否为 False,那我为什么不能这样写呢?
if greeting == False:
如果我写 if not greeting:
,这和上面的语句意思就完全不同了。如果 greeting 是 None 呢?如果它是一个空字符串呢?这个 PEP 8 的建议是不是意味着存储布尔值的变量只能包含 True 或 False,而不应该用 None 呢?
在我看来,这个建议像是来自其他有静态类型的语言,而在Python中不太适用,至少在比较 False 的时候是这样。
顺便问一下,为什么 if greeting is True:
被认为比 if greeting == True:
更糟糕?我们是不是也应该理解 if greeting is False:
也比 if greeting == False:
更糟糕呢?
6 个回答
不使用 ==
或 !=
来比较真假,最简单的原因可能是:
0 is False # Result: False
0 == False # Result: True; 0 evaluates comparatively to False
1 is True # Result: False
1 == True # Result: True; 1 evaluates comparatively to True
is
是用来检查传入的值是否是 完全 等于 True
或 False
,而不是检查它是否 能被理解为 True
或 False
。
这种行为让我们可以这样做:
if var is False:
# False (bool) case
elif var is None:
# None case
elif var == 0:
# integer 0 case
而
if var == False:
# catches False & 0 case; but not None case, empty string case, etc.
这看起来有点反直觉——这就是我认为 PEP 8 会说“不要这样做”的原因。
正如在这里所说,使用 is
来判断 身份,而使用 ==
来判断 相等。
你只应该在需要布尔值 True
的时候使用 if var is True
,但又想排除 1
、'某个字符串'
等等。
这种情况对大多数读者来说可能不太明显;我怀疑 PEP 8 认为这样做是“更糟”的,因为可能会造成误解。偶尔这样做可能是不得已的;但是……如果你发现自己需要 is True
,这 可能 表示设计上有问题。无论如何,如果你真的使用 is
,你可能应该注释一下“为什么”你需要 确切 的 True
或 False
。
我觉得你可能理解错了。不要把 greeting
看成一个名词,更应该把它当成一个动词来理解(就像“我在打招呼”而不是“这就是一个问候”)。
你可以在PEP8的开头找到一些线索:
Guido的一个重要观点是,代码被阅读的频率远高于被编写的频率。这里提供的指导方针旨在提高代码的可读性。
为了这个目的,代码应该尽量像书面或口头语言一样。你在生活中不会说 "如果我让你烦恼是真的,请告诉我"
,你只会说 "如果我让你烦恼,请告诉我"
。
这就是为什么你经常看到像 isOpen
和 hasBeenProcessed
这样的布尔变量,因为它们有助于提高代码的可读性。
你绝对不应该这样做:
if (isOpen == True)
或者:
if (customerDead == False)
仅仅因为你在变量名中已经有一个布尔值。所有的相等比较只会给你 另一个 布尔值,推理到极端的话,你会在哪里停止呢?
if (isComplete == True) ...
if ((isComplete == True) == True) ...
if (((isComplete == True) == True) == True) ...
if ((((isComplete == True) == True) == True) == True)...
我理解的PEP建议是,如果你对foo
的类型有比较把握(通常情况都是这样),那么检查它是否等于假值就显得多余,而且会降低代码的可读性。例如,在foo = [i for i in range(10) if i == x]
这行代码中,你可以相当确定foo
唯一可能的假值就是[]
(假设没有出现异常)。在这种情况下,使用foo == []
就显得多余,使用not foo
会更好。
另一方面,foo == []
或者foo == False
的语义价值有时更重要,应该在这种情况下使用(这是我的个人看法),而不是用not foo
。这取决于你具体想要表达什么。实际上,not foo
的意思是“foo
有一个假值吗?”,而foo == False
的意思是“foo
的值和False
一样吗?”
PEP中说明它所包含的内容都是一些指导原则。规则总是有例外,这条规则也不例外。