关于比较布尔值与True或False的奇怪PEP8建议

23 投票
6 回答
13870 浏览
提问于 2025-04-16 06:16

在我阅读Python的PEP 8时,最后提到:

  • 不要用 == 来比较布尔值是否为 True 或 False

     Yes:   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 个回答

8

不使用 ==!= 来比较真假,最简单的原因可能是:

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 是用来检查传入的值是否是 完全 等于 TrueFalse,而不是检查它是否 能被理解为 TrueFalse

这种行为让我们可以这样做:

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,你可能应该注释一下“为什么”你需要 确切TrueFalse

20

我觉得你可能理解错了。不要把 greeting 看成一个名词,更应该把它当成一个动词来理解(就像“我在打招呼”而不是“这就是一个问候”)。

你可以在PEP8的开头找到一些线索:

Guido的一个重要观点是,代码被阅读的频率远高于被编写的频率。这里提供的指导方针旨在提高代码的可读性。

为了这个目的,代码应该尽量像书面或口头语言一样。你在生活中不会说 "如果我让你烦恼是真的,请告诉我",你只会说 "如果我让你烦恼,请告诉我"

这就是为什么你经常看到像 isOpenhasBeenProcessed 这样的布尔变量,因为它们有助于提高代码的可读性。

你绝对不应该这样做:

if (isOpen == True)

或者:

if (customerDead == False)

仅仅因为你在变量名中已经有一个布尔值。所有的相等比较只会给你 另一个 布尔值,推理到极端的话,你会在哪里停止呢?

if (isComplete == True) ...
if ((isComplete == True) == True) ...
if (((isComplete == True) == True) == True) ...
if ((((isComplete == True) == True) == True) == True)...
4

我理解的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中说明它所包含的内容都是一些指导原则。规则总是有例外,这条规则也不例外。

撰写回答