如果我们想在循环中使用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。
答案 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秒