Pythonic /在Python继续表现

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)

Aya*_*Aya 6

在这种情况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我可以说,算法正常运行所需.