【问题标题】:Is it Pythonic to use bools as ints?将布尔值用作整数是 Pythonic 吗?
【发布时间】:2011-03-11 14:30:07
【问题描述】:

False 等价于0True 等价于1,所以可以这样做:

def bool_to_str(value):
    """value should be a bool"""
    return ['No', 'Yes'][value]

bool_to_str(True)

注意值是bool,但用作int

这种使用Pythonic还是应该避免?

【问题讨论】:

标签: boolean python


【解决方案1】:

我将成为奇怪的声音(因为所有答案都在谴责使用 False == 0True == 1 作为语言保证的事实),因为我声称使用这一事实来简化您的代码是完全没问题。

历史上,逻辑真/假操作倾向于简单地使用0 表示假,1 表示真;在 Python 2.2 的生命周期中,Guido 注意到太多的模块以 false = 0; true = 1 之类的赋值开始,这产生了样板和无用的变化(后者是因为 true 和 false 的大写无处不在——一些使用全大写,一些全小写,一些大写首字母),因此引入了intbool 子类及其TrueFalse 常量。

当时有相当多的阻力,因为我们中的许多人担心 Python 新手会使用新类型和常量来限制该语言的能力,但 Guido 坚持认为我们只是被悲观:没有人会如此糟糕地理解 Python,例如,为了避免完全自然地使用 FalseTrue 作为列表索引、求和,或其他非常清晰和有用的习语。

这个帖子的答案证明我们是对的:正如我们所担心的那样,对这种类型和常量的角色的完全误解出现了,人们正在回避,而且,更糟糕的是!敦促其他人避免使用完全自然的 Python 构造来支持无用的旋转。

与这种误解的浪潮作斗争,我敦促大家把 Python 当作 Python 来使用不要试图将它强加到其他语言的模式中,这些语言的功能和风格偏爱完全不同。 在 Python 中,True 和 False 有 99.9% 与 1 和 0 相似,完全在它们的 str(...)(因此是 repr(...))形式上有所不同——对于 每个 除了字符串化之外的其他操作,请随意使用它们而不会扭曲。这适用于索引、算术、位操作等。

【讨论】:

  • +1 与 Ruby 对比,如果您需要将 bool 视为 int,则会强制使用 val?1:0 和类似的体操垃圾。
  • “例如,没有人会如此糟糕地理解 Python,以至于避免将 False 和 True 完全自然地用作列表索引”。我当然不反对以这种方式使用它们,但我绝不认为人们用布尔类型索引到列表中是“自然的”,除非他们碰巧知道 bool 子类 int
  • 确实很有趣的历史课!然而,我认为大多数人区分布尔值和整数这一事实有一定的意义(我确实......)。在某种程度上,人们正在定义“将 Python 用作 Python”的含义:我们大多数人确实认为这两种类型之间存在逻辑上的区别(数学大多也是如此:逻辑不需要算术)。我很高兴 Python 允许我们这样思考。
  • 正如 dahlia 的回答所示,索引方法具有不必要的限制性(与 … if … else … 方法相比)。
  • 我不敢相信我不同意亚历克斯,但我确实同意。在这种情况下使用布尔值作为索引可以避免鸭子类型,而'True' if value else 'False' 可以与任何真实的value 一起使用。
【解决方案2】:

我和亚历克斯在一起。 False==0True==1,这并没有错。

不过,在 Python 2.5 及更高版本中,我会使用 Python 的条件表达式来写下这个特定问题的答案:

def bool_to_str(value):
  return 'Yes' if value else 'No'

这样就不需要参数实际上是布尔值——就像if x: ... 接受x 的任何类型一样,bool_to_str() 函数在传递 None、字符串、a 时应该做正确的事情列表,或 3.14。

【讨论】:

    【解决方案3】:

    肯定的:

    def bool_to_str(value):
        "value should be a bool"
        return 'Yes' if value else 'No'
    

    更具可读性。

    【讨论】:

    • 我会和那个争论......是的,使用x if foo else y 的东西更像是pythonic,但我仍然认为它看起来很丑而且经常膨胀代码。我认为问题中的代码看起来更清晰,对于不了解隐式 bool 到 int 转换的人可能会感到困惑,但 x if foo else y 对于来自foo ? x : y 事物世界。尽管我不得不承认,对于正在学习第一语言的人来说,x if foo else y 可能是最清晰的。
    • @Ivo,+1,因为我同意该实质内容,但我不同意“三元”构造(条件在中间,而不是像 C 中那样在开头)特别自然或清晰对新手来说(在许多情况下,这是最轻的——那是另一回事;-)。
    • 不确定,看起来我也有一个,大约在同一时间(而且还没有 cmets!)。
    • 来吧,@AlexMartelli,Python 的“三元”结构如此很自然,它可以直接阅读为简单的英语,甚至非程序员也能理解。 “如果为真则返回是,否则返回否”。这对新手来说是一种优雅和自然语言的祝福。
    【解决方案4】:

    您的代码在某些情况下似乎不准确:

    >>> def bool_to_str(value):
    ...     """value should be a bool"""
    ...     return ['No', 'Yes'][value]
    ...
    >>> bool_to_str(-2)
    'No'
    

    为了便于阅读,我建议您只使用条件运算符:

    def bool_to_str(value):
        """value should be a bool"""
        return "Yes" if value else "No"
    

    【讨论】:

    • 函数的名字是bool_to_str,带有文档注释value should be a bool,你很惊讶当你传递它时它给出了错误的答案-2:)
    • 另一方面,我认为通常假设非 0 表示 True... dahlia 的示例表明 … if … else … 方法允许您生成没有不必要限制的代码.
    • +1 虽然我总体上同意 Alex Martelli 的回答,但在这种情况下,利用 ... if ... else ... 提供的对 bool 的隐式转换似乎“更像 Pythonic”。然后该函数适用于布尔值和其他任何东西。虽然可能不是最好的例子,因为我不同意将布尔值用作整数的想法。
    • 如果您不知道您收到的值是严格布尔值(即TrueFalse)还是“真实表达式”(例如a and b or c),那么只需应用bool 函数的值。简单!
    【解决方案5】:

    False == 0 和 True == 1 其实是语言的一个特性(不依赖于实现):Is False == 0 and True == 1 in Python an implementation detail or is it guaranteed by the language?

    但是,我同意大多数其他答案:通过使用… if value else … 或字典,有更多可读的方法可以获得与['No', 'Yes'][value] 相同的结果,它们具有各自的提示优势并声明 value 是一个布尔值。

    另外,… if value else … 遵循非 0 为 True 的常规约定:即使 value == -2(值为 True)也可以使用,正如 dahlia 所暗示的那样。在这种情况下,list 和 dict 方法没有那么健壮,所以我不推荐它们。

    【讨论】:

      【解决方案6】:

      使用 bool 作为 int 是完全可以的,因为 bool 是 int 的子类。

      >>> isinstance(True, int)
      True
      >>> isinstance(False, int)
      True
      

      关于你的代码:把它放在一个像这样的单行函数中是最重要的。读者需要找到你的函数源或文档并阅读它(函数的名称并不能告诉你太多)。这会中断流动。只需将其内联,不要使用列表(在运行时构建),使用元组(如果值是常量,则在编译时构建)。示例:

      print foo, bar, num_things, ("OK", "Too many!)[num_things > max_things]
      

      【讨论】:

        【解决方案7】:

        我个人认为这取决于你想如何使用这个事实,这里有两个例子

        1. 只需简单地使用布尔作为条件语句就可以了。人们一直都在这样做。

          a = 0
          if a:
              do something
          
        2. 但是说你要统计有多少项成功了,代码可能对其他人阅读不太友好。

          def succeed(val):
              if do_something(val):
                  return True
              else:
                  return False
          
          count = 0
          values = [some values to process]
          for val in values:
              count += succeed(val)
          

        但我确实看到生产代码是这样的。

        all_successful = all([succeed(val) for val in values])
        at_least_one_successful = any([succeed(val) for val in values])
        total_number_of_successful = sum([succeed(val) for val in values])
        

        【讨论】:

          最近更新 更多