And*_*ley 4 python logic loops
我不确定这应该是在cs或程序员堆栈交换中,所以如果它应该让我知道.我知道在其他语言中,它continue可能会成为问题,因为它本质上执行无条件分支,这会导致流水线机器上的性能问题,因为为了有效地管道,我们需要能够知道接下来会有什么指令,无条件分支可以防止.这可以通过使用更坚固的逻辑来防止.话虽如此,我知道在Python中,continue可以提高循环内的性能,但是,我希望不仅仅是轶事证据来支持这一点.任何人都可以详细说明为什么在Python中就是这种情况?是否continue在Python中使用被认为是"正确"的逻辑(即Pythonic)?谢谢!
我也对性能影响感到好奇.如上所述,在其他语言中,continue基本上是无条件分支.显然,这可能会导致流水线机器出现性能问题.所以我很好奇,continue在Python中使用时是否存在固有的性能开销,即使在循环中使用时会有性能提升?
这里是示例代码(尝试重新插入插入排序,忽略整体逻辑,这源于一些尝试获得优于O(n 2)性能的实验),如果我们有一个案例可以确定下一个元素应该在哪里go(在头部或尾部),我们可以轻松地将它放在那里并使用该continue语句忽略循环的其余部分
def insertion_sort(array):
sublist = [array[0]]
for i in range(1, len(array)):
if array[i] >= sublist[i-1]:
sublist.append(array[i])
continue #possible performance loss here
if array[i] <= sublist[0]:
sublist.insert(0, array[i])
continue #possible performance loss here
for j in reversed(range(0, i)):
if array[i] >= sublist[j-1] and array [i] <=sublist[j]:
sublist.insert(j, array[i])
break #possible performance loss here
return sublist
Run Code Online (Sandbox Code Playgroud)
在这种情况continue下,在相互排斥的条件下,您将用作"选择"的手段.考虑以下更简单的例子......
def f1():
for i in range(10):
if i < 5:
print 'i is less than 5'
if i > 5:
print 'i is greater than 5'
def f2():
for i in range(10):
if i < 5:
print 'i is less than 5'
continue
if i > 5:
print 'i is greater than 5'
Run Code Online (Sandbox Code Playgroud)
这两个函数将产生相同的输出,但在第一种情况下,假设我们知道i同时不能同时大于和小于5,则第一个函数执行不必要的比较,并且可能需要更长的时间来执行.
第二个例子更常见的表达为......
def f3():
for i in range(10):
if i < 5:
print 'i is less than 5'
elif i > 5:
print 'i is greater than 5'
Run Code Online (Sandbox Code Playgroud)
至于哪个性能更高,你可以看一下Python dis模块,它可以f2()产生...
0 SETUP_LOOP 63 (to 66)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (10)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 49 (to 65)
16 STORE_FAST 0 (i)
19 LOAD_FAST 0 (i)
22 LOAD_CONST 2 (5)
25 COMPARE_OP 0 (<)
28 POP_JUMP_IF_FALSE 42
31 LOAD_CONST 3 ('i is less than 5')
34 PRINT_ITEM
35 PRINT_NEWLINE
36 JUMP_ABSOLUTE 13
39 JUMP_FORWARD 0 (to 42)
>> 42 LOAD_FAST 0 (i)
45 LOAD_CONST 2 (5)
48 COMPARE_OP 4 (>)
51 POP_JUMP_IF_FALSE 13
54 LOAD_CONST 4 ('i is greater than 5')
57 PRINT_ITEM
58 PRINT_NEWLINE
59 JUMP_ABSOLUTE 13
62 JUMP_ABSOLUTE 13
>> 65 POP_BLOCK
>> 66 LOAD_CONST 0 (None)
69 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
......而且f3()......
0 SETUP_LOOP 60 (to 63)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (10)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 46 (to 62)
16 STORE_FAST 0 (i)
19 LOAD_FAST 0 (i)
22 LOAD_CONST 2 (5)
25 COMPARE_OP 0 (<)
28 POP_JUMP_IF_FALSE 39
31 LOAD_CONST 3 ('i is less than 5')
34 PRINT_ITEM
35 PRINT_NEWLINE
36 JUMP_ABSOLUTE 13
>> 39 LOAD_FAST 0 (i)
42 LOAD_CONST 2 (5)
45 COMPARE_OP 4 (>)
48 POP_JUMP_IF_FALSE 13
51 LOAD_CONST 4 ('i is greater than 5')
54 PRINT_ITEM
55 PRINT_NEWLINE
56 JUMP_ABSOLUTE 13
59 JUMP_ABSOLUTE 13
>> 62 POP_BLOCK
>> 63 LOAD_CONST 0 (None)
66 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
...... 39 JUMP_FORWARD由于先前的无条件跳跃,第一个例子中唯一可能永远不会被执行的显着差异,但是使用它来决定哪个"更好"将优化变为荒谬的水平.
这两个例子f2()和f3()只有真正风格上有所不同.考虑...
def f4():
while 1:
if expr1:
do_something()
else:
if expr2:
do_something_else()
if expr3:
do_a_different_thing()
def f5():
while 1:
if expr1:
do_something()
continue
if expr2:
do_something_else()
if expr3:
do_a_different_thing()
Run Code Online (Sandbox Code Playgroud)
...功能相同,但f5()最小化嵌套块的压痕水平,这对于较窄的固定宽度显示更为理想.至于哪个更"可读",那纯粹是主观的.
回到你的代码,你可以同样表达为......
def insertion_sort(array):
sublist = [array[0]]
for i in range(1, len(array)):
if array[i] >= sublist[i-1]:
sublist.append(array[i])
elif array[i] <= sublist[0]:
sublist.insert(0, array[i])
else:
for j in reversed(range(0, i)):
if array[i] >= sublist[j-1] and array [i] <=sublist[j]:
sublist.insert(j, array[i])
break #possible performance loss here
return sublist
Run Code Online (Sandbox Code Playgroud)
...这将消除continues,但正如dis模块所示,这样做没有性能优势.至于break我可以说,算法正常运行所需.