在python中为什么显式bool比隐式

时间:2018-04-09 14:41:38

标签: python performance python-3.6

给出以下三个功能

def v1(a):
    c = 0
    for a_ in a:
        if a_ is not None:
            c += 1
    return c

def v2(a):
    c = 0
    for a_ in a:
        if a_:
            c += 1
    return c

def v3(a):
    c = 0
    for a_ in a:
        if bool(a_):
            c += 1
    return c

我得到以下表现(我在ubuntu 18.04上使用python 3.6)

values = [random.choice([1, None]) for _ in range(100000)]

%timeit v1(values)
3.35 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit v2(values)
2.83 ms ± 36.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit v3(values)
12.3 ms ± 59.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

v1v2之间的类似效果是有道理的,但为什么v3速度慢得多,因为v2可能也隐含地调用了bool(a_)

它只是从python而不是c(我假设bool()那样)调用if会导致性能上的差异吗?

2 个答案:

答案 0 :(得分:3)

这主要是由于Python的动态性以及你有Python级别调用的事实。

使用bool Python无法直接构建新的bool对象。它必须查找以找到与bool完全相关的内容;然后它检查是否可以调用它,解析它的参数和  然后打电话给它。

使用if _a等构造具有明确的含义。如果加载的值具有真值,它将通过特定的OPCODE(此处为POP_JUMP_IF_FALSE)和checks。减少箍跳的方式。

bool调用same function来检查提供的值是True还是False,它只有更长的行程才能到达。

答案 1 :(得分:1)

v2能够评估"真实性"在解释器中的a_

 >>> dis.dis(v2)
 ...
 11          14 LOAD_FAST                2 (a_)
             16 POP_JUMP_IF_FALSE       10
 ...

在Python级别实际调用v3需要bool

>>> dis.dis(v3)
...
18          14 LOAD_GLOBAL              0 (bool)
            16 LOAD_FAST                2 (a_)
            18 CALL_FUNCTION            1
            20 POP_JUMP_IF_FALSE       10
...

函数调用会降低v3的速度。