19

在 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:的话,就会和上面的说法有很大不同的意思。如果问候语是无怎么办?如果它是一个空字符串怎么办?这个 PEP 8 建议是否意味着存储布尔值的变量应该只包含 True 或 False 并且这些变量应该避免 None ?

在我看来,它看起来像是来自其他具有静态类型的语言的推荐,并且不适合 Python,至少与 False 相比。

顺便说一句,为什么被if greeting is True:描述为比if greeting == True:?我们是否也应该明白那if greeting is False:也更糟if greeting == False:

4

6 回答 6

18

我相信你读错了。尽量不要将greeting名词视为动词(“我在打招呼”而不是“这是打招呼”)。

您可以在 PEP8 的序言中看到线索:

Guido 的主要见解之一是阅读代码的频率远高于编写代码的频率。此处提供的指南旨在提高代码的可读性。

为此,代码应该尽可能地类似于书面或口头文字。"If I am annoying you is true, let me know"在现实生活中你不说,你只是说"If I am annoying you, let me know"

这就是为什么您倾向于看到类似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)...
于 2010-10-29T09:33:33.063 回答
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,而不是计算结果是否为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所说的用于身份==用于平等

您只想if var is True在需要 bool 值时使用True,但想要拒绝1,'some string'等。

这种情况对大多数读者来说可能并不明显;我怀疑 PEP 8 声称它“更糟糕”是因为它可能具有误导性。有时它可能是一种必要的邪恶;但是...如果您发现自己需要is True,则可能表明存在设计问题。在任何情况下,您都应该评论“为什么”您需要确切地 True或者False如果您曾经使用过is.

于 2015-04-30T00:27:47.483 回答
5

这是鸭子打字的一部分。在 Python 中,您通常不希望将接受的内容限制为特定的类,而是限制为公开适当 API 的对象。例如,我可以这样做:

class MyProperty(object):
    """
    A file-backed boolean property.
    """
    def __init__(self, filename):
        self.value = open(filename).read()
    def __nonzero__(self):
        return self.value != "0"
    def save_to_disk(self):
        # ... and so on
        pass

def func(enabled):
    if not enabled:
        return
    # ...

enable_feature = MyProperty("enable_feature")
func(enable_feature)

if enabled == False会导致这不起作用。

False 是一个错误值,但它不是唯一的错误值。避免与 True 和 False 进行比较,原因与避免使用isinstance.

于 2010-10-29T09:24:51.580 回答
4

我理解 PEP 建议的方式意味着,如果您可以合理地确定 的类型foo(通常是这种情况),那么测试显式 false 值是多余的,并且会降低可读性。例如,在 中foo = [i for i in range(10) if i == x],您可以相当确定唯一的 false 值foo[](假设没有引发异常)。在这种情况下,使用它是多余的foo == []并且not foo更好。

另一方面,foo == []or的语义价值foo == False有时更有价值,因此应该使用(恕我直言)而不是not foo. 这取决于你想要沟通的具体内容。事实上not foo 意味着foo一个错误的价值?”,而foo == False 意味着foo有相同的价值False?”。

PEP 声明它包含的所有内容都是指南。规则有例外,这一点也不例外。

于 2010-10-29T10:22:51.233 回答
1

我不确定其他评论是否回答了您的问题。你说:

如果我这样写if not greeting:的话,就会和上面的说法有很大不同的意思。如果问候语是无怎么办?如果是空字符串怎么办?

确实,not greeting而且greeting == False有不同的含义。但是 PEP 8 并没有说相反,也没有说不使用greeting == False. 它说:

不要使用 == 将布尔值与 True 或 False 进行比较

空字符串都不None是布尔值。因此greeting == False,如果合适,可以使用并且greeting可以是非布尔值。


有人在您的问题下方评论:

... 为什么有时是 None,有时是 bool,有时是 str?那只是自找麻烦。

那不是。这是一个用例:您有一个患者数据库,其中有一个字段说明患者是否死于自杀。假设我们有Patient带有属性的类suicidesuicide将有三个可能的值:

  • True意思是“是的,我们知道他自杀了”
  • False意思是“不,我们知道他死于别的东西”
  • None意思是“我们实际上不知道”。

然后,如果您想研究不会死于自杀的患者,您可以执行以下操作:

# load database
...

# Filter patients
database = [patient for patient in database if patient.suicide == False]  # if greeting == False:

# Study database
...

QED。这是数据科学中的典型案例。价值False意味着你知道某事是假的,而价值None意味着你什么都不知道。

于 2019-08-23T17:34:34.877 回答
0

我通常在模式之后命名我的布尔变量IsName,所以在你的情况下它是IsGreeting。这使得检查读取if IsGreeting/ if not IsGreeting,这是非常直观的。

您所描述的歧义是if not在布尔比较中使用非布尔类型的结果。这通常应该避免,因为它非常令人困惑。

于 2010-10-29T08:54:47.767 回答