Python中列表的布尔值

Posted

技术标签:

【中文标题】Python中列表的布尔值【英文标题】:bool value of a list in Python 【发布时间】:2012-04-08 15:57:37 【问题描述】:

将列表转换为布尔值的最佳方法是什么?我正在寻找类似的东西:

return eval_bool(my_list)

我有一个自定义容器,我在其中实现了 __nonzero__ 方法,它应该像这样工作:

if self.my_list:
    return True
return False

但它足够pythonic吗? :) 无论如何,我很好奇 Python 如何解释 if 语句中列表的值,因为这段代码的工作方式不同:

return my_list == True

J.

【问题讨论】:

【参考方案1】:

99.9% 的情况下,性能并不重要,所以只需将 bool(my_list) 用作 Keith suggests。

在性能确实很重要的情况下,bool 的性质意味着它实际上很慢,至少在 CPython 参考解释器上是这样。它必须经过通用函数调用路径、通用构造函数路径、通用参数解析 0-1 参数(在all but the most recent versions of Python 中,检查关键字参数),所有这些最终都只是作为单例上的引用计数递增并返回它。

您可以通过ipython 微基准(在我的 Windows x64 3.6.3 版本上)查看此成本:

In [1]: %%timeit -r5 l = []
   ...: bool(l)
   ...:
118 ns ± 0.808 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)
In [11]: %%timeit -r5 l = [1]
    ...: bool(l)
    ...:
117 ns ± 0.306 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

这可能并不明显,但即使在我相对较弱的笔记本电脑上,117-118 纳秒只是为了确定真实性有点多。幸运的是,还有其他几个选择。一种是滥用语法通过专用路径进行真实性评估(从这里开始,我将只测试空的list,两种方式的时间基本相同):

In [3]: %%timeit -r5 l = []
   ...: not not l
   ...:
25 ns ± 0.289 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

这是一个巨大的进步;大约需要五分之一的时间。在 Python 3 上,使用 True if l else False 也能以相同的速度工作,但它比 Python 2 上的 not not 慢得多,其中 TrueFalse 不是受保护的文字,只是必须动态加载的内置名称每次。

不过,它并不完美;有时您需要一个可调用对象,例如通过回调函数(例如使用map)将大量值转换为bool。幸运的是,the operator module 覆盖了with operator.truth;虽然它仍然是一个带有所有开销的可调用对象,但它不是构造函数,它需要恰好一个参数(不是 0-1),并且它不允许关键字参数,所有这些都需要花费CPython 参考解释器的数量惊人。因此,当您无法使用 not not 的隐式真实性测试或基于语法的转换,并且您仍然需要速度时,operator.truth 可以满足您的需求:

In [4]: from operator import truth

In [5]: %%timeit -r5 l = []
   ...: truth(l)
   ...:
52.1 ns ± 1.1 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

两倍于not not,但如果您使用它与重复调用它的内置插件(如map)能够将所有工作推送到C层,完全避免字节码执行,仍然可以成功,而且成本仍远低于bool() 本身的一半。

重申我之前的观点:99.9% 的情况下,性能并不重要,所以只需将 bool(my_list) 用作 Keith suggests。 我只提到这一点因为我曾经有一个场景,布尔转换确实是我的代码中最热点(通过分析验证),并且使用隐式真实性测试(甚至不转换,只是返回 list 调用者执行 if myfunc():)剃光 30运行时折扣 %,返回 list 中的 not not 仍可节省近 20%。

【讨论】:

【参考方案2】:

您可以使用三元“if”运算符。谷歌表示它从 2.5 开始支持

foo = True if your_list else False

【讨论】:

注意:在 Python 2 中,至少对于 CPython 参考解释器来说,这非常慢,因为 TrueFalse 都是全局内置函数,必须从内置函数加载命名空间(涉及一对字典查找,一个用于全局变量,然后在未找到时在内置函数中查找),而不是文字常量。在 Python 3 中,它们是文字常量,只需要一个廉价的 LOAD_CONST 指令即可加载(归结为单个 C 级数组查找),因此这是转换为 bool 的两种最快方法之一(另一个是not not your_list)。【参考方案3】:

如果len(my_list) == 0返回false,否则返回true。写起来完全是pythonic:

return len(my_list)

虽然它以整数形式返回,但对于非零长度的计算结果为 true,否则为 false。

【讨论】:

然而,这将返回整数值,我们需要一个布尔值。 它有效,但它违反了 pep 8:对于序列(字符串、列表、元组),使用空序列为假的事实。 Yes: if not seq: if seq: No: if len(seq) if not len(seq)【参考方案4】:

只需使用:

bool(my_list)

将其评估为 Python“真实性”并返回一个真正的布尔值。

【讨论】:

虽然可以使用bool,但更符合Pythonic 的方式是调用if my_list: 并让Python 确定my_list 的计算结果是True 还是False @SimeonVisser:为什么if my_list: return True\nreturn Falsereturn bool(my_list) 更pythonic? 当你也可以写if my_list:时,写if bool(my_list):并不常见。在大多数情况下,您只需要检查列表是否为空,您并不需要布尔值。 Python 可以看到您正在评估一个 if 语句,它会调用 bool() 本身。如果你真的是一个布尔值(例如,作为输出),那么bool(my_list) 当然可以。 @SimeonVisser 这里的目标根本不是条件逻辑,而是返回一个布尔值。

以上是关于Python中列表的布尔值的主要内容,如果未能解决你的问题,请参考以下文章

计算 Python 列表中真正布尔值的数量

Python:将字符串列表转换为布尔值,其中布尔值以字符串形式存在[重复]

有没有办法提取发生短路的 Python 布尔值列表的索引?

Python中的布尔值列表到整数

Python:如何检查列表是不是包含数值并返回布尔值?

Python:项目的子列表取决于项目的某个值,例如布尔值