Python:for循环+中断vs while +标志性能

时间:2019-02-10 11:17:04

标签: python performance

如果我们想在循环中使用while语句,我们的编程老师建议使用for循环而不是return循环,前提是“ Python优化了{{ 1}}通过在为它提供表格时展开它来循环,因此如果在中间放置for,则会浪费内存和时间。”

我使用Python已经有好几年了,根据Python规范,我可以肯定地说这是错误的(如果循环的主体是“简单的”,则只有CPython才能进行循环展开)。

基本上他是说这段代码:

return

将导致性能问题,应替换为

def check_five(tab):
    for elem in tab:
        if elem > 5:
            return True
    return False

既不那么Python,也更肿。

我已经做了一些基准测试,def check_five(tab): i = 0 found = False while i < len(tab) and not found: if tab[i] > 5: found = True i += 1 return found 的速度大约是while的3倍。

他的推理中有什么道理吗? (是否有可能是真的?)

注意:这不是关于何时使用for循环或for循环的问题,不是问题,这是关于两者的表现。我也知道使用while编写此代码的更好方法,但是很遗憾,我们只允许使用我们已经在课堂上介绍的内容。另外,我们使用的是Python 3。

4 个答案:

答案 0 :(得分:2)

只需向您的老师显示dis的输出(无双关语)。

from dis import dis

def for_check_five(tab):
    for elem in tab:
        if elem > 5:
            return True
    return False


def while_check_five(tab):
    i = 0
    found = False
    while i < len(tab) and not found:
        if tab[i] > 5:
            found = True
        i += 1
    return found


dis(for_check_five)
print()
print('--------------')
print()
dis(while_check_five)

输出

104           0 SETUP_LOOP              24 (to 26)
              2 LOAD_FAST                0 (tab)
              4 GET_ITER
        >>    6 FOR_ITER                16 (to 24)
              8 STORE_FAST               1 (elem)

105          10 LOAD_FAST                1 (elem)
             12 LOAD_CONST               1 (5)
             14 COMPARE_OP               4 (>)
             16 POP_JUMP_IF_FALSE        6

106          18 LOAD_CONST               2 (True)
             20 RETURN_VALUE
             22 JUMP_ABSOLUTE            6
        >>   24 POP_BLOCK

107     >>   26 LOAD_CONST               3 (False)
             28 RETURN_VALUE

--------------

111           0 LOAD_CONST               1 (0)
              2 STORE_FAST               1 (i)

112           4 LOAD_CONST               2 (False)
              6 STORE_FAST               2 (found)

113           8 SETUP_LOOP              44 (to 54)
        >>   10 LOAD_FAST                1 (i)
             12 LOAD_GLOBAL              0 (len)
             14 LOAD_FAST                0 (tab)
             16 CALL_FUNCTION            1
             18 COMPARE_OP               0 (<)
             20 POP_JUMP_IF_FALSE       52
             22 LOAD_FAST                2 (found)
             24 POP_JUMP_IF_TRUE        52

114          26 LOAD_FAST                0 (tab)
             28 LOAD_FAST                1 (i)
             30 BINARY_SUBSCR
             32 LOAD_CONST               3 (5)
             34 COMPARE_OP               4 (>)
             36 POP_JUMP_IF_FALSE       42

115          38 LOAD_CONST               4 (True)
             40 STORE_FAST               2 (found)

116     >>   42 LOAD_FAST                1 (i)
             44 LOAD_CONST               5 (1)
             46 INPLACE_ADD
             48 STORE_FAST               1 (i)
             50 JUMP_ABSOLUTE           10
        >>   52 POP_BLOCK

117     >>   54 LOAD_FAST                2 (found)
             56 RETURN_VALUE

告诉您的老师while循环还需要完成多少工作。您拥有的+分析数据应该说服您和您的老师谁是正确的。

答案 1 :(得分:0)

嗯,这个while循环比较慢,因为会发生更多的事情:每次迭代都要检查两个条件,在while块中为列表建立索引,您要执行与for循环相同的检查,并在其中加1一世。如果要比较for和while的性能,最好在两者中进行相同数量的工作。

答案 2 :(得分:0)

我更喜欢any(x>5 for x in tab) ..但为了使while循环更快,您可以花时间:

def check_five(tab):
    i = 0
    len_tab = len(tab)-1
    while tab[i] <= 5 and i < len_tab:
         i += 1
    return tab[i] > 5

这省去了您在 while循环中执行的一些操作:

  • 用保存该值的局部变量替换len(tab)
  • 删除一些不需要使用的变量和条件
def while_check_five(tab):
    i = 0
    found = False                         # dont need this
    while i < len(tab) and not found:     # dont need len(tab) every loop - if mutable
        if tab[i] > 5:                    # it might neeed reevaluation in each loop
            found = True                  # dont need this
        i += 1
    return found

答案 3 :(得分:0)

我已经测试了以上所有答案。而且尽管您的while函数没有经过优化,但您是对的。

此外,For循环的速度几乎是使用的两倍:

any(x>5 for x in tab)

似乎For循环获胜。

代码:

import time


def check_five_f(tab):
    """For loop"""
    for elem in tab:
        if elem > 5:
            return True
    return False

def check_five_w(tab):
    """While loop"""
    i = 0
    found = False
    while i < len(tab) and not found:
        if tab[i] > 5:
            found = True
        i += 1
    return found

def check_five_o(tab):
    """Optimized While loop"""
    i = 0
    len_tab = len(tab)-1
    while i < len_tab:
        if tab[i] > 5:
            return True
        i += 1
    return False

def check_five_l(tab):
    return any(x>5 for x in lst)


lst = list(range(-100000000, 10))

# For loop
start = time.time()
check_five_f(lst)
print("For loop : ",time.time() - start, " sec")

#While loop
start = time.time()
check_five_w(lst)
print("While loop : ",time.time() - start, " sec")

# Optimised while loop
start = time.time()
check_five_o(lst)
print("Optimised while loop : ",time.time() - start, " sec")

# List comprehension loop
start = time.time()
check_five_l(test)
print("Using any with List comprehension  : ",time.time() - start, " sec")
  

输出:

     

For循环:3.4106831550598145秒
  While循环:20.234021186828613秒
  优化while循环:9.381998538970947 sec
  使用以下任何内容进行列表理解:6.175985813140869秒