为什么 if x in (1,2,3): 比 if x ==1 or x ==2 or x ==3 更快:

Why is if x in (1,2,3): faster than if x ==1 or x ==2 or x ==3:

根据 http://pylint.pycqa.org/en/latest/whatsnew/2.0.html in 选项比 multiple or 更快。

引用本站

A new check was added, consider-using-in.

This refactoring message is emitted when a variable is compared against multiple values concatenated by ors instead of using the faster, more idiomatic "in" check.

if variable == 1 or variable == 2 or variable == 3: # bad pass

if variable in (1, 2, 3): # good pass

首先,in选项是否更快?因为肯定它必须和多个 or 做同样的事情,难道每次创建元组的内存损失不值得吗?

一方面,constant-folding optimization 会预先计算常量元组,因此 in (1, 2, 3) 不会每次都构建整个元组。无需每次都构建元组,in 方法实际上比 == 方法具有更少的字节码解释开销并且运行速度更快。

另一方面,这只适用于常量元组。当元组不是编译时常量时,in 通常较慢,例如 in (x, y, z)。 Pylint 将报告 consider-using-in,即使在 in 速度较慢的情况下也是如此。

我认为 Pylint 甚至会在 in 会改变代码含义的情况下报告 consider-using-in,例如 x == 1 or x == thing_with_side_effects().

通常情况下,我认为 pylint 是错误的。情况并非总是如此。 只有 元组可以在字节码编译步骤中作为常量缓存,但情况并非总是如此。考虑简单的:

In [1]: def using_in(a, b, c):
   ...:     42 in (a,b,c)
   ...:

In [2]: def using_or(a, b, c):
   ...:     42 == a or 42 == b or 42 == c
   ...:

In [3]: %timeit using_in(1,2,3)
125 ns ± 3.82 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [4]: %timeit using_or(1,2,3)
119 ns ± 1.96 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

但更重要的是,这类决策几乎总是与代码清晰度或可维护性有关。无论如何,性能差异通常可以忽略不计。

老实说,如果您正在编写代码以在此级别进行优化,CPython 可能不适合您。