【问题标题】:Why is `len(l) != 0` faster than `bool(l)` in CPython?为什么在 CPython 中 `len(l) != 0` 比 `bool(l)` 快?
【发布时间】:2019-12-16 04:35:22
【问题描述】:

我正在对列表中的操作速度进行一些实验。为此,我定义了两个列表:l_short = []l_long = list(range(10**7))

这个想法是将bool(l)len(l) != 0进行比较

if 竞赛中,以下实现要快很多if l: pass 而不是if len(l) != 0: pass

但没有 if 比赛我得到了以下结果:

%%timeit
len(l_long) != 0
# 59.8 ns ± 0.358 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%%timeit
bool(l_long)
# 63.3 ns ± 0.192 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

bool的时间稍长,为什么呢?

这是使用 dis 的字节码(仅供参考)

dis("len(l_long) != 0")
"""
  1           0 LOAD_NAME                0 (len)
              2 LOAD_NAME                1 (l_long)
              4 CALL_FUNCTION            1
              6 LOAD_CONST               0 (0)
              8 COMPARE_OP               3 (!=)
             10 RETURN_VALUE
"""

dis("bool(l_long)")
"""
  1           0 LOAD_NAME                0 (bool)
              2 LOAD_NAME                1 (l_long)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE
"""

【问题讨论】:

标签: python python-3.x performance cpython


【解决方案1】:

bool(l_long)首先尝试调用l_long.__bool_();但是,list.__bool__ 没有定义。下一步是致电l_long.__len__() != 0

另一方面,len(l_long) != 0 直接转到l_long.__len__()

您看到的时间差本质上是在调用l_long.__len__ 之前捕获l_long.__bool__ 引发的AttributeError 所需的时间。

【讨论】:

  • 非常感谢您的回答。作为旁注,我认为if l_long: pass 隐含地称为bool(l),我显然错了。 if l_long: pass 发生了什么?
  • 我认为bool()也很慢还有其他原因,请在此处阅读cmets stackoverflow.com/questions/48909056/…
  • 如果您查看if l_long: pass 的字节码,您会看到它直接跳转到POP_JUMP_IF_FALSE,而无需在字节码级别调用任何函数。
  • @chepner,我注意到了,这是否意味着解释器会照顾我们下面的一些优化?
  • 基本上。当您编写bool(l_long) 时,解析器只看到您正在调用绑定到名称bool 的东西;因此,字节码生成器不能假设 bool 仍然绑定到内置类型 bool (至少不会比您希望解析器做的工作更多),因此必须对其进行处理像任何其他函数调用一样。另一方面,使用if l_long,在运行时没有任何内容可以被覆盖:l_long 用于布尔上下文,句号,因此您可以直接跳到解释器中隐藏的好东西。跨度>
猜你喜欢
  • 2022-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 2019-04-12
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
相关资源
最近更新 更多