Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any case in python when using a while loop would be best practice?

I'm doing some python benchmarking, and I've discovered that repeat(None) is much faster than while True or while 1:

>>> def bench7():
...   foo = 0
...   a = time()
...   for i in repeat(None):
...     foo += 1
...     if foo == 100000000:
...       break
...   b = time()
...   print a, b, b-a
... 
>>> def bench8():
...   foo = 0
...   a = time()
...   while True:
...     foo += 1
...     if foo == 100000000:
...       break
...   b = time()
...   print a, b, b-a
... 
>>> bench7()
1326592924.41 1326592935.42 11.0051281452
>>> bench7()
1326592936.36 1326592947.48 11.1183578968
>>> bench8()
1326592951.47 1326592965.03 13.5640599728
>>> bench8()
1326592966.07 1326592979.6 13.5341670513`

This sort of usage for a while loop was the last thing that I actually used while loops for. Is there any reason left to use whiles that I'm overlooking?

like image 794
OmnipotentEntity Avatar asked Jan 15 '12 02:01

OmnipotentEntity


2 Answers

The while True is only slower because of the global lookup for True. If you use while 1 instead, the while-loop should handily beat the for-repeat (at least in terms of speed, beauty, and clarity):

>>> from dis import dis
>>> def f():
        while True:
            print

>>> dis(f)
  2           0 SETUP_LOOP              11 (to 14)
        >>    3 LOAD_GLOBAL              0 (True)
              6 POP_JUMP_IF_FALSE       13
  3           9 PRINT_NEWLINE       
             10 JUMP_ABSOLUTE            3
        >>   13 POP_BLOCK           
        >>   14 LOAD_CONST               0 (None)
             17 RETURN_VALUE        

>>> def g():
        while 1:
            print

>>> dis(g)
  2           0 SETUP_LOOP               4 (to 7)
  3     >>    3 PRINT_NEWLINE       
              4 JUMP_ABSOLUTE            3
        >>    7 LOAD_CONST               0 (None)
             10 RETURN_VALUE    

The main use case for repeat is to supply a stream of constant values to imap or izip. For example, the following computes the sum of powers-of-two: sum(imap(pow, repeat(2), xrange(10))).

The repeat itertool can also be used to speed-up a for-loop that doesn't need a changing variable. For example, Guido used this technique to minimize looping overhead in the timeit module: http://hg.python.org/cpython/file/40e1be1e0707/Lib/timeit.py#l188

To answer your other question, "are there any reasons to use a while-loop". The answer is yes. Python's for-loop is really a foreach that consumes iterators to produce a stream of values. In contrast, a while-loop is either unbounded (as in the while-True example) or terminated when a specific condition is met (for example, looping over user inputs until the user types "quit" or somesuch).

The contrasting capabilities of while-loops and for-loops can be seen in the example of the Collatz conjecture where the while-loop cannot be easily replaced with a for-loop:

def collatz(n):
    print n
    while n > 1:
        n = n // 2 if n % 2 == 0 else n * 3 + 1
        print n

Many more examples and use cases for while-loops can be seen by grepping over Python's standard library.

In summary, the while-statement is an essential part of your toolkit :-)

like image 107
Raymond Hettinger Avatar answered Nov 14 '22 21:11

Raymond Hettinger


While loops allow for truth-value testing.

while x < y:

Is it possible that's why it is slower than repeat?

like image 29
Joel Cornett Avatar answered Nov 14 '22 21:11

Joel Cornett