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
慢得多,其中 True
和 False
不是受保护的文字,只是必须动态加载的内置名称每次。
不过,它并不完美;有时您需要一个可调用对象,例如通过回调函数(例如使用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 参考解释器来说,这非常慢,因为True
和 False
都是全局内置函数,必须从内置函数加载命名空间(涉及一对字典查找,一个用于全局变量,然后在未找到时在内置函数中查找),而不是文字常量。在 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 False
比return bool(my_list)
更pythonic?
当你也可以写if my_list:
时,写if bool(my_list):
并不常见。在大多数情况下,您只需要检查列表是否为空,您并不需要布尔值。 Python 可以看到您正在评估一个 if 语句,它会调用 bool()
本身。如果你真的是一个布尔值(例如,作为输出),那么bool(my_list)
当然可以。
@SimeonVisser 这里的目标根本不是条件逻辑,而是返回一个布尔值。以上是关于Python中列表的布尔值的主要内容,如果未能解决你的问题,请参考以下文章