就 efficiency/quickly 拒绝事物而言,您的 if 语句是否在同一行是否重要?

In terms of efficiency/quickly rejecting things, does it matter if your if statements are on the same line?

例如,假设我想找到 1 到 1000 之间所有可被 3 和 5 整除的数字。代码:

for i in range(1,1000):
    if i % 3==0 and i %5 == 0:
        blah

效率不如说

for i in range(1,1000):
    if i%3==0:
       if i%5==0:
           blah

计算机是否检查这两个条件?例如,如果 i=10。第一个中的计算机会同时计算 i%3 和 i%5,还是会计算 i%3 然后中断?在那种情况下,将 easy to check/reject 条件放在左边会更有效率,对吗?

不,只要其中一个条件为假,它就会return假。这称为短路。参见 python docs

在python和许多语言中有short circuit evaluation的布尔表达式。这意味着一旦我们确定布尔表达式的真值,评估就会停止。在这方面,您的两个代码片段是等效的。

但是您可以通过更改顺序进行优化。例如,最好使用:

if i % 5 == 0 and i % 3 == 0

原因是数字很少是 5 的倍数,因此在大多数情况下此表达式会更早失败。

例如,如果我们检查从 1 到 150 的数字,则检查 i % 5 == 0 将失败 120 个数字。因此,我们将对 i % 5 == 0 执行 120 次检查,对 i % 5 == 0i % 3 == 0 执行 30 次检查。总共有 180 张支票。同样,对于 if i % 3 == 0 and i % 5 == 0,我们将执行 100 + 2 * 50 = 200 检查。

除了解释 short-circuiting 的其他答案外,两者都做一份工作,性能之间没有太大差异。

查看以下基准:

s1="""
for i in range(1,1000):
    if i % 3==0 and i %5 == 0:
        pass
"""
s2="""
for i in range(1,1000):
    if i%3==0:
       if i%5==0:
           pass

    """


print ' first: ' ,timeit(stmt=s1, number=1000)
print 'second : ',timeit(stmt=s2, number=1000) 

结果:

 first:  0.0738339424133
second :  0.0790829658508

如您所见,区别在于 0.006,这是因为在第二部分加载了额外的块。

您也可以使用 dis 模块反汇编 python 字节码:

第一个循环使用 and :

 21           0 SETUP_LOOP              58 (to 61)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1)
              9 LOAD_CONST               2 (1000)
             12 CALL_FUNCTION            2
             15 GET_ITER            
        >>   16 FOR_ITER                41 (to 60)
             19 STORE_FAST               0 (i)

 22          22 LOAD_FAST                0 (i)
             25 LOAD_CONST               3 (3)
             28 BINARY_MODULO       
             29 LOAD_CONST               4 (0)
             32 COMPARE_OP               2 (==)
             35 POP_JUMP_IF_FALSE       16
             38 LOAD_FAST                0 (i)
             41 LOAD_CONST               5 (5)
             44 BINARY_MODULO       
             45 LOAD_CONST               4 (0)
             48 COMPARE_OP               2 (==)
             51 POP_JUMP_IF_FALSE       16

 23          54 JUMP_ABSOLUTE           16
             57 JUMP_ABSOLUTE           16
        >>   60 POP_BLOCK           
        >>   61 LOAD_CONST               0 (None)
             64 RETURN_VALUE 

第二个:

26           0 SETUP_LOOP              61 (to 64)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (1)
              9 LOAD_CONST               2 (1000)
             12 CALL_FUNCTION            2
             15 GET_ITER            
        >>   16 FOR_ITER                44 (to 63)
             19 STORE_FAST               0 (i)

 27          22 LOAD_FAST                0 (i)
             25 LOAD_CONST               3 (3)
             28 BINARY_MODULO       
             29 LOAD_CONST               4 (0)
             32 COMPARE_OP               2 (==)
             35 POP_JUMP_IF_FALSE       16

 28          38 LOAD_FAST                0 (i)
             41 LOAD_CONST               5 (5)
             44 BINARY_MODULO       
             45 LOAD_CONST               4 (0)
             48 COMPARE_OP               2 (==)
             51 POP_JUMP_IF_FALSE       60

 29          54 JUMP_ABSOLUTE           60
             57 JUMP_ABSOLUTE           16
        >>   60 JUMP_ABSOLUTE           16
        >>   63 POP_BLOCK           
        >>   64 LOAD_CONST               0 (None)
             67 RETURN_VALUE