就 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 == 0
和 i % 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
例如,假设我想找到 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 == 0
和 i % 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