Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `len(l) != 0` faster than `bool(l)` in CPython?

I was doing some experimentation about operations' speed on list. For this I defined two list: l_short = [] and l_long = list(range(10**7)).

The idea is to compare bool(l) with len(l) != 0

In an if contest, the following implementation is faster by a lot if l: pass instead of if len(l) != 0: pass

But without the if contest I got the following results:

%%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)

The timing of bool is slightly longer, why so ?

Here are the bytecodes using dis (FYI)

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
"""
like image 836
BlueSheepToken Avatar asked Aug 08 '19 12:08

BlueSheepToken


1 Answers

bool(l_long) first tries to call l_long.__bool_(); however, list.__bool__ isn't defined. The next step is to call l_long.__len__() != 0.

len(l_long) != 0, on the other hand, goes straight to l_long.__len__()

The time difference you see is essentially the time it takes to catch the AttributeError raised by l_long.__bool__ before calling l_long.__len__ anyway.

like image 169
chepner Avatar answered Nov 11 '22 11:11

chepner