将布尔值用作整数是Pythonic吗?


67

False等效于0True等效,1因此可以执行以下操作:

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

bool_to_str(True)

请注意value是如何bool使用的,但用作int

这是Pythonic的这种用法还是应该避免?


1
这本质上是stackoverflow.com/questions/2764017/…的副本,其答案也引起了有趣的阅读!
Eric O Lebigot

Answers:


168

我会很奇怪(因为所有答案都拒绝使用False == 0andTrue == 1保证语言的使用),因为我声称使用该事实来简化您的代码是完全可以的。

从历史上看,逻辑上的正确/错误运算往往简单地0用于false和1true。在Python 2.2的整个生命周期中,Guido注意到太多的模块以诸如这样的赋值开头,false = 0; true = 1这会产生样板和无用的变化(后者是因为对正误的大写处处存在-有些使用了全部-caps,一些全小写,一些帽初始)等介绍了bool的子类int和其TrueFalse常数。

由于当时我们中的许多人担心Python新手会使用新类型和常量来限制该语言的功能,因此出现了很多回退,但是Guido坚持认为我们只是悲观:没有人会如此糟糕地理解Python,例如,为了避免完全自然地使用FalseTrue作为列表索引,或者避免总和,或者避免其他如此清晰而有用的习惯用法。

该线程的答案证明我们是正确的:正如我们所担心的那样,人们对这种类型和常量的作用已经产生了完全的误解,人们正在回避,更糟糕的是,敦促其他人避免使用完全自然的Python构造,而赞成没用的回转。

为了应对这种误解,我敦促每个人都将Python用作Python而不是试图将其引入功能和偏好样式完全不同的其他语言中。 在Python中,True和False像1和0一样为99.9%,唯一不同的是它们的形式str(...)(因此repr(...))不同-对于除字符串化之外的所有其他操作,可以随意使用它们而不会产生扭曲。用于索引,算术,位运算等,等等,等等。


9
+1与Ruby形成对比,val?1:0如果您需要将布尔值当作int来使用,则它会强迫和类似的体操垃圾。
John La Rooy

26
“例如,没有人会如此严重地理解Python,以至于避免完全自然地使用False和True作为列表索引”。我当然不反对以这种方式使用它们,但我绝不认为人们索引布尔类型的列表是“自然的”,除非他们碰巧知道这些bool子类int
Michael Mrozek,2010年

3
确实有趣的历史课!但是,我会说一个事实,那就是大多数人都将布尔值和整数区分开(我确实……)。从某种意义上说,人们正在定义“将Python用作Python”的含义:我们大多数人确实认为这两种类型之间存在逻辑上的区别(数学也是如此:逻辑不需要算术)。我对Python允许我们以这种方式思考这一事实感到非常满意。
Eric O Lebigot

如大丽花的答案所示,索引方法不必要地受到限制(与该… if … else …方法相比)。
Eric O Lebigot

1
我不敢相信我不同意亚历克斯,但我同意。在这种情况下,使用布尔值作为索引可以避免鸭子输入,而'True' if value else 'False'可以使用任何truish value
mcepl '16

146

我和亚历克斯在一起。False==0True==1,这没有任何问题。

不过,在Python 2.5及更高版本中,我仍将使用Python的条件表达式编写此特定问题的答案:

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

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


38

一定:

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

更具可读性。


2
我会与那个争论……是的,使用x if foo else ythingy更具Python风格,但我仍然认为它看起来很难看,而且经常使代码膨胀。我认为问题中的代码看起来更清晰,对于不了解隐式布尔值向int转换的人来说,这可能会令人困惑,但x if foo else y对于来自foo ? x : y事物世界的人来说,也可能令人困惑。即使我不得不承认,对于正在学习母语的人们来说,这x if foo else y可能是最清晰的语言。
伊沃·韦策尔

2
@Ivo,我同意该内容为+1,但是我不同意“三元”构造(中间条件,而不是像C那样在开始时)对于新手来说特别自然或清楚(这是最少的邪恶)在许多情况下-这是另一回事;-)。
Alex Martelli

不确定,看起来我也差不多同时拿到了一个(也没有评论!)。
Alex Martelli'7

1
拜托,Python的“三元”构造@AlexMartelli非常自然,可以直接将其读为普通英语,即使是非程序员也可以理解。“如果是,则返回“是,否则返回“”。这对新手来说是一种优雅和自然语言的祝福。
MestreLion

14

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

>>> 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"

17
该函数的名称为bool_to_str,带有doc comment value should be a bool,当您通过该函数时,它给出了错误的答案,您感到惊讶-2:)
Michael Mrozek 2010年

另一方面,我认为通常会假设非0表示True。大丽花的例子表明,该… if … else …方法允许您产生不必要的限制代码。
Eric O Lebigot

4
+1虽然我与亚历克斯·马尔泰利在一般的回答一致,在这种情况下,它似乎“更Python”,以采取隐式转换的优势,bool通过提供... if ... else ...。然后,该功能适用​​于布尔值和其他任何功能。虽然也许不是最好的例子,但我不同意将布尔值用作整数的想法。
anton.burger 2010年

如果您不知道接收到的值是严格的布尔值(即TrueFalse)还是“真实的表达式”(例如a and b or c),则只需将bool函数应用于该值。简单!
Holdenweb '16

5

这实际上是False == 0和True == 1(不依赖于实现)的语言特征:Python中False == 0和True == 1是实现细节还是由该语言保证?

但是,我确实同意其他大多数答案:['No', 'Yes'][value]通过使用… if value else …或字典,可以获得与相同的结果的更具可读性的方式,它们分别具有提示和声明value布尔值的优点。

另外,… if value else …遵循大写非0的通常约定:value == -2大丽花暗示,即使(value为True),它也可以使用。在这种情况下,list和dict方法不那么健壮,因此我不推荐它们。


1

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

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

关于您的代码:将其放在上面的单行函数中。读者需要找到您的函数源或文档并阅读(函数名称并不能告诉您太多)。这中断了流程。只需将其内联,不要使用列表(在运行时构建),而使用元组(如果值是常量,则在编译时构建)。例:

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

0

我个人认为这取决于您如何使用此事实,这是两个示例

  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])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.