Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

End loop with counter and condition

Tags:

python

loops

In Python I can implement a loop with step counter and a stop condition as a classical case of for loop :

for i in range(50):
    result = fun(i)
    print(i, result)
    if result == 0: 
        break

where fun(x) is some arbitrary function from integers to integers.

I always in doubts if that is the best way to code it (Pythonically, and in terms of readability and efficiency) or is it better to run it as a while loop:

i = 0
result = 1
while result != 0 and i < 50:
    result = fun(i)
    print(i, result)
    i += 1

which approach is better? In particular - I'm concerned about the usage of break statement which doesn't feel right.

like image 685
Dimgold Avatar asked Jun 11 '17 07:06

Dimgold


2 Answers

The for loop is slightly more performant than the while because range() is implemented in C, meanwhile the += operation is interpreted and requires more operations and object creation/ destruction. You can illustrate the performance difference using the timeit module, for example:

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 

The for loop is arguably more Pythonic in the vast majority of cases when you wish to iterate over an iterable object. Furthermore, to quote the Python wiki: "As the for loop in Python is so powerful, while is rarely used except in cases where a user's input is required". There is nothing un-Pythonic about using a break statement per se.

Readability is mostly subjective, I would say the for loop is more readable too, but it probably depends on your previous programming background and experience.

like image 140
Chris_Rands Avatar answered Sep 20 '22 01:09

Chris_Rands


If efficiency is what you are looking for then use generator functions

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
    ...:   

The result of %timeit in ipython

The slowest run took 6.15 times longer than the fastest. This could mean that an intermediate result is being cached. 10000 loops, best of 3: 30.9 µs per loop

like image 43
theBuzzyCoder Avatar answered Sep 21 '22 01:09

theBuzzyCoder