【问题标题】:pep8 minor annoyancepep8 小烦恼
【发布时间】:2014-01-27 23:29:33
【问题描述】:

/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 的相等性,最佳实践是什么?使用isTrue 进行身份检查是否可以?为什么 pep8 实用程序提供了 pep8 本身明确不鼓励的替代方案?

【问题讨论】:

  • 你为什么要检查一个整数变量,看看它是否是一个布尔值?
  • 为什么需要显式测试True 值?如果您确实必须测试True,则使用is True
  • FWIW,PEP 8 确实说“不要将布尔值与 True 或 False [...] 进行比较”,而您所拥有的不是布尔值。虽然...是的,当 PEP 说情况更糟时,该工具建议 is 有点奇怪。不过,您的最后一个问题可能应该问该工具的开发人员。

标签: python boolean pep8


【解决方案1】:

为什么需要显式测试True 值?如果确实需要,您很少需要将测试范围缩小到特定类型。我会在这里重新考虑您的用例;如果您正在构建的 API 将针对带外条件返回 bool 而不是 int,请改用异常。

如果您确实必须测试True ,则使用

if n is True:

因为布尔值意味着像None 这样的单例。见Programming recommendations section

应始终使用 isis not 与诸如 None 之类的单例进行比较,而不是使用相等运算符。

另外,因为issubtype(bool, int)为真(由于历史原因;bool在Python中被引入相当晚),n == Truen = 1也为真,如果你在这里只能接受True那么你可以只使用is True。您也可以使用isinstance(n, bool) and n,这将允许bool 的子类,但我无法想象这种类型有什么用处,在当前的实现中,bool explicitly prohibits being subclassed

PEP 8 关于不使用 if cond is True: 的规则被特别指出因为它将cond 的值限制为仅bool

最后但同样重要的是,PEP 8 starts with this

愚蠢的一致性是小聪明的妖精

[...] 但最重要的是:知道何时不一致——有时风格指南并不适用。如有疑问,请使用您的最佳判断。查看其他示例并决定什么看起来最好。

仅在符合您的需求时才遵循 PEP 8。

【讨论】:

  • 我现在不想挖掘邮件列表消息,但 Guido 明确拒绝了这种结构(在请求从 PEP 8 中删除禁令的情况下)。他的建议是x and isinstance(x, bool),进一步警告说,如果你正在编写这段代码,那么给你x的API是可怕的,你应该改正它。
  • @Wooble:我发现情况更糟;是否期望True 会有不止一个 副本? Python 3 制作了 TrueFalse 关键字,因此您不能为这两个名称分配其他值,进一步巩固了它们是单例的事实。
  • @Wooble:啊,我想你可以subclass bool 并提供更多值。我发现bool 子类可能有用的建议不太可能。更好地修复产生这个想法的 API..
  • 这不是理由。 if x is True: 保证在语言规范中正常工作。它的风格不好的原因是,当任何人写它几乎总是一个错误时,编写代码的人可能会认为他们的意思是if x:,然后“修复”它。我不确定这实际上是禁止它的一个很好的理由(就像我确定不允许在条件中分配一样,因为人们经常在允许的语言中混淆===),但是,正如你所说,这是一个风格指南,如果你不是为 stdlib 编写的,请忽略它。 :)
  • 对于上下文,我在对 API 进行单元测试时遇到了这个问题,其中一些代码应该返回文字 True,并且正在使用 == 进行检查
【解决方案2】:

如果您确实需要使用True 检查相等性,请使用== 并忽略 PEP8,但几乎在任何可能的情况下,这都不是您想要的。

如果您想知道您拥有的值是否是 Python 认为正确的值之一,请使用if cond:。如果您想知道您拥有的值是否是单例值True,则使用is True,布尔值TrueFalse 是单例,因此在这种情况下使用is 是正确的。

如果您需要测试您的对象是否是单例 True,但 linter 或代码审查员抱怨 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 == 真为真,69 == 真为假
  • 记住False == 0True == 1 因为issubtype(bool, int) 是真的..
  • 谢谢@Ant,这是我的解释缺失的例子。
  • 另请注意,在 Python 2 中,TrueFalse 是可以分配给的变量(与 None 不同)。这在 Python 3 中有所改变。
【解决方案3】:

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

【讨论】:

  • cond = 2 -> 现在if cond:if cond == True: 之间存在差异。
【解决方案4】:

无论你做什么,我认为需要注释,因为代码看起来很有趣。

如果您想检查与True 是否相等,那么写if n == 1 可能更清楚。阅读代码的人不太可能将其误解为测试逻辑真理的尝试。

当然,如果n 有一个用户定义的类型,可能定义n.__eq__ 这样(n == True) != (n == 1),但这会很讨厌。因此,您必须决定是否可以通过避免代码看起来像不正确的逻辑真值测试来证明含义上的细微差别。

如果差异不合理,并且如果您绝对需要编写 PEP8 样式指南,请使用 assertEqual 或编写 expected_value = Trueif n == expected_value

如果代码是 API 的单元测试,由于某种原因明确定义了返回文字 True,那么当然您应该测试 if n is True,而不是 if n == True。和以前一样,需要注释或某种间接方式来阻止代码看起来不正确。

另一种选择是更改您正在测试的 API。样式指南规则的部分原因是阻止人们发明或依赖专门定义返回值必须与文字 True 相同或相等的 API,而是根据逻辑定义 API 和编写代码真相。因此,如果您“修复”API,您就可以“修复”测试它的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 2011-12-17
    • 2014-01-02
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 2017-04-15
    相关资源
    最近更新 更多