在Python中,我可以实现一个带步进计数器和停止条件的循环,作为 for loop 的经典案例:
for i in range(50):
result = fun(i)
print(i, result)
if result == 0:
break
其中fun(x)
是从整数到整数的任意函数。
我总是怀疑这是否是编码的最佳方法( Pythonically ,以及可读性和效率)或者是最好将其作为 while循环:
运行i = 0
result = 1
while result != 0 and i < 50:
result = fun(i)
print(i, result)
i += 1
哪种方法更好?特别是 - 我担心break
语句的用法感觉不对。
答案 0 :(得分:14)
for
循环的效果略高于while
因为range()
is implemented in C,同时+=
操作被解释,需要more operations和对象创建/销毁。您可以使用timeit
module来说明性能差异,例如:
from timeit import timeit
def for_func():
for i in range(10000):
result = int(i)
if result == -1:
break
def while_func():
i = 0
result = 1
while result != -1 and i < 10000:
result = int(i)
i += 1
print(timeit(lambda: for_func(), number = 1000))
# 1.03937101364
print(timeit(lambda: while_func(), number = 1000))
# 1.21670079231
for
循环可以说是more Pythonic in the vast majority of cases when you wish to iterate over an iterable object。此外,引用Python wiki:&#34;因为Python中的for循环非常强大,但很少使用,除非需要用户输入&#34;。关于使用break
语句本身,没有任何非Pythonic。
可读性主要是主观的,我会说for
循环也更具可读性,但它可能取决于您之前的编程背景和经验。
答案 1 :(得分:6)
性能差异很小。由于while循环在每次迭代时执行额外的布尔检查,因此稍慢。
但是,对于您想要评估的大多数功能,首先使用循环可以替代,这样会更快。见下面的例子。我确信还有更优化的实施方案..
import time
def fun(step):
return step == 50000000
t1 = time.time()
for i in range(500000000):
result = fun(i)
# print(i, result)
if result == 1:
break
print("time elapsed", time.time() - t1)
t2 = time.time()
i = 0
result = 0
while result != 1 and i < 50000000:
result = fun(i)
# print(i, result)
i += 1
print("and here", time.time() - t2)
import numpy as np
t3 = time.time()
foo = np.arange(500000000)
i = np.where(foo == 50000000)
print("Alternative", time.time()-t3)
时间已过去11.082087516784668
和14.429940938949585
替代方案1.4022133350372314
如果你想/必须使用一个循环,那么for循环通常是更多的Pythonic方式,如解释in this nice answer to a related question
编辑:Chris Rands的回答从C代码的角度解释了它,并且使用了更准确的(尽管在我强迫这个例子的宏观层面上,这并不重要)时序模块。也请阅读他的答案。答案 2 :(得分:4)
最好的方法是不要明确循环。 itertools救援:
from itertools import takewhile
it = ((x, f(x)) for x in range(50)) # first you define the resulting view
it = takewhile(lambda y: y[1] != 0, it) # define when to stop iterating
list(map(print, it)) # if you want to print it
+它比循环
要快得多答案 3 :(得分:3)
纯粹看字节码,while-loop得到30行,for-loop得到26行。
最后,不要认为这很重要,但我个人更喜欢for-loop版本,因为它更容易阅读。
我使用的代码:
def fun(i):
i = i + 1
return i
def test1():
i = 0
result = 1
while result != 0 and i < 50:
result = fun(i)
print(i, result)
i += 1
def test2():
for i in range(50):
result = fun(i)
print(i, result)
if result == 0:
break
答案 4 :(得分:1)
我非常确定在比较而和 循环时,不应该关心性能,因此主要问题是可读性。
首先,当然
for i in range(50):
result = fun(i)
print(i, result)
if result == 0:
break
比
好多了i = 0
result = 1
while result != 0 and i < 50:
result = fun(i)
print(i, result)
i += 1
因为在阅读简单循环
时,不需要记住一些类似C的变量@ quidkid的解决方案非常优雅,但这是一个很好的观点
it = takewhile(lambda y: y[1] != 0, ((x, f(x)) for x in range(50)))
仅适用于非常简单的示例,并且会丢失可读性,因为您需要添加一些额外的功能
正如我所看到的,代码中的主要问题是你的函数不纯,所以也许你应该这样做:
def some_generator():
for i in range(50):
result = fun(i)
yield result, i
if result == 0:
return
for x in some_generator():
print x
do_something_else_with(x[1])
答案 5 :(得分:1)
采用函数方法,创建一个执行操作的本地闭包并返回终止谓词的值。然后迭代输入直到完成。
def action(i):
result = fun(i)
print(i, result)
return result == 0
list(itertools.takewhile(action, range(50))) # non-pythonic wasted list
终止一系列行动的另一种方法是:
terminated = reduce(lambda done, i: done or action(i), range(50), False) # extra unnecessary iterations
看起来我们又回到了pythonicness的break
声明
for i in range(50):
if action(i):
break
答案 6 :(得分:0)
如果您正在寻找效率,那么请使用生成器功能
In [1]: def get_result():
...: for i in xrange(50):
...: result = fun(i)
...: yield result, i
...: if result == 0:
...: break
...:
In [2]: generator_func = get_result()
In [3]: for result, i in generator_func:
...: print result, i
...:
ipython中%timeit的结果
最慢的跑步比最快跑的时间长6.15倍。这可以 表示正在缓存中间结果。 10000循环,最好的 3:每循环30.9μs
答案 7 :(得分:-1)
根本不需要break语句... for循环将自动终止。您所需要的只是:
for i in range(50):
result = fun(i)
print(i, result)
这将永远是更可读的imho。