结束循环与计数器和条件

时间:2017-06-11 07:23:07

标签: python loops

在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语句的用法感觉不对。

8 个答案:

答案 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版本,因为它更容易阅读。

http://mergely.com/9P1cfnTr/

我使用的代码:

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。