PEP8小烦恼

5
/tmp/spam.py 中:
n = 69

if n == True:
    print 'potato'

pep8工具报错了,说这个条件语句有问题:

wim@SDFA100461C:/tmp$ pep8 spam.py 
spam.py:3:6: E712 comparison to True should be 'if cond is True:' or 'if cond:'
  • 第一个建议根据pep8本身是错误/“更糟”的
  • 第二个建议改变了代码的行为

如果您确实希望检查与True相等,最佳实践是什么?使用is进行身份检查是否可以?为什么pep8实用程序提供了一种明确不被pep8本身鼓励的替代方案?


为什么要检查一个整数变量,看它是否是布尔型? - aIKid
1
为什么需要显式测试“True”值?如果您只需要测试“True”,则使用“is True”。 - Martijn Pieters
3
PEP 8指出“不要将布尔值与True或False进行比较[...]”,而您所拥有的不是布尔值。尽管......是的,工具建议使用is,但PEP说这样做更糟。不过,您最后一个问题可能应该询问工具的开发人员。 - Wooble
4个回答

8
如果您确实需要检查与True的相等性,请使用==并忽略PEP8,但在几乎任何情况下,这不是您想要的。
如果您想知道您拥有的值是否是Python认为为真的值之一,请使用if cond:。 如果您想知道您拥有的值是否为单例值True,则使用is True,布尔值True和False是单例值,因此在这种情况下使用is是正确的。
如果您需要测试对象是否为单例True,但linter或code reviewer抱怨is True,则isinstance(x,bool)and x是行为上等效(但速度较慢)的替代品。
检查x == True是一种过渡方法。 当x is True为真时,它为真,并且对于您的情况x = 69为假,但是还有其他对象它们本身不是True,但是x == True给出意外的真结果,例如1 == True为真。(感谢@Ant)
因此,将其放在一起:
value of n:    True  1     69     False   0
-----------------------------------------------
expression     result
-----------------------------------------------
if n:          True  True  True   False   False
if n is True:  True  False False  False   False
if n==True:    True  True  False  False   False

从表中选择那一行,使其返回你真正想要的结果(最后一行并不是)。

1
1 == True 是真的,而 69 == True 是假的。 - Ant
1
请记住 False == 0True == 1,因为 issubtype(bool, int) 是真的。 - Martijn Pieters
1
谢谢@Ant,那个例子是我解释中缺失的。 - Duncan
还要注意,在Python 2中,TrueFalse是可以被赋值的变量(不像None)。但在Python 3中已经改变了。 - augurar

2

无论您做什么,在看代码时,我认为都需要添加注释,因为它看起来很有趣。

如果您想检查与 True 的相等性,则编写 if n == 1 可能会更清晰。阅读代码的人不太可能将其解释为测试逻辑真值的尝试。

当然,如果 n 有用户定义的类型,则可以定义 n.__eq__,使得 (n == True) != (n == 1),但这可能会非常讨厌。因此,您必须决定是否通过避免代码看起来像错误的逻辑真值测试来证明微妙的差异是合理的。

如果区别不合理,并且您绝对需要按照 PEP8 样式指南编写,则使用 assertEqual 或编写 expected_value = Trueif n == expected_value

如果代码是 API 的单元测试,由于某种原因,API 特别定义了返回字面量 True,则当然应该测试 if n is True,而不是 if n == True。如前所述,需要添加注释或一些间接手段以防止代码出错。

另一个选择是更改您正在测试的 API。样式指南规则的原因部分在于鼓励人们不要发明或依赖特别定义返回值必须与字面量 True 相同或相等的 API,而是定义 API 并根据逻辑真值编写代码。因此,如果您“修复”API,则可以“修复”测试它的代码。


1
为什么需要显式测试True值?你很少需要将测试缩小到特定类型。我会重新考虑你的用例;如果你正在构建一个API,它将返回bool而不是int用于带外条件,则应使用异常。
如果你确实需要仅测试True,那么使用
if n is True:

因为布尔值意味着像None这样的单例。请参见编程建议部分

None等单例进行比较应始终使用isis not,而不是等式运算符。

此外,由于issubtype(bool, int)为真(出于历史原因;bool在Python中引入得相当晚),如果你只能接受True,那么n == True对于n = 1也为真,则你只能使用is True。你还可以使用isinstance(n, bool) and n,这将允许bool的子类,但我无法想象会有这种类型的用途,在当前实现中,bool明确禁止被子类化
PEP 8规则中关于不使用if cond is True:的规定是特别提出来的,因为它将cond的值限制在bool上。

最后,PEP 8 从这里开始

愚蠢的一致性是小心眼的鬼怪

[...] 但最重要的是:知道何时不一致--有时样式指南并不适用。 如果不确定,请使用最佳判断力。 查看其他示例并决定哪个看起来最好。

只有在符合您需求的情况下才遵循PEP 8。


1
我现在不想去找邮件列表中的信息,但Guido明确拒绝了这种构造方式(在请求从PEP 8中删除禁令的情况下)。他的建议是x and isinstance(x, bool),并进一步警告说,如果你正在编写这段代码,那么提供给你x的API是可怕的,你应该先修复它。 - Wooble
@Wooble:啊,我想你可以子类化 bool 并提供更多的值。我认为一个 bool 子类可能有用的建议有些不太可能;最好修复产生这个想法的 API。 - Martijn Pieters
1
那不是理由。在语言规范中,“if x is True:”保证能够正确工作。它的不好之处在于,当任何人编写时,几乎总是一个错误,而编写代码的人可能会认为他们意味着“if x:”,然后“修复”它。我不确定这是否真的是禁止它的好理由(就像我不确定是否不允许在条件语句中进行赋值,因为人们经常在允许的语言中混淆“=”和“==”一样),但正如你所说,这是一个风格指南,如果你不是为stdlib编写代码,可以忽略它。 :) - Wooble
为了上下文,我在API的单元测试中遇到了这个问题,其中一些代码应该返回字面值“True”,并且正在使用“==”进行检查。 - wim
@wim:在这种情况下,断言返回的类型是 bool 并完成它。assertTrue(n)assertTrue(isinstance(n, bool)) - Martijn Pieters
显示剩余7条评论

-2
第二个建议最适合您的需求。条件语句if cond:如果条件本身为真,则返回true。它不会改变代码的行为,因为它只是if cond == True:的简写形式。

现在cond = 2的情况下,if cond:if cond == True:之间有所不同。 - Andras Deak -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接