2

It is common to express for loops as list comprehensions:

mylist=[]
for i in range(30):
    mylist.append(i**2)

This is equivalent to:

mylist = [i**2 for i in range(30)]

Is there any sort of mechanism by which this sort of iteration could be done with a while loop?

mylist=[]
i=0
while i<30:
    mylist.append(i**2)
    i+=1

Of course with this simple example it's easy to translate to a for loop and then to a list comprehension, but what if it isn't quite so easy?

e.g.

mylist = [i**2 while i=0;i<30;i++ ]

(Of course the above pseudo-code isn't legitimate python) (itertools comes to mind for this sort of thing, but I don't know that module terribly well.)

EDIT

An (very simple) example where I think a while comprehension would be useful would be:

dt=0.05
t=0
mytimes=[]
while t<maxtime:
   mytimes.append(t)
   t+=dt

This could translate to:

dt=0.05
t=0
nsteps=maxtime/dt
mytimes=[]
for t in (i*dt for i in xrange(nsteps)):
    mytimes.append(t)

which can be written as a (compound) list comprehension:

nsteps=maxtime/dt
mytimes=[t for t in (i*dt for i in xrange(nsteps)] 

But, I would argue that the while loop is MUCH easier to read (and not have index errors) Also, what if your object (dt) supports '+' but not '*'? More complicated examples could happen if maxtime somehow changes for each iteration of the loop...

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 3
    "but what if it isn't quite so easy?": can you give such an example? (one that is not translatable into a for-loop) – Pavel May 17 '12 at 13:55
  • What if the upper bound in the loop changes in the loop? e.g. what if it is `while i<30*math.sqrt(i): ...` – mgilson May 17 '12 at 14:00

1 Answers1

9

If your while loop justs checks a local variable that is being incremented, you should convert it to a for loop or the equivalent list comprehension.

You should only use a while loop only if you can not express the loop as iterating over something. An example of a typical use case are checks for the state of an Event, or a low-level loop that calls into native code. It follows that (correctly used) while loops are rare, and best just written out. A while comprehension would just make them harder to read.

If you just want to return multiple values, you should consider writing a generator.

For example, your edited algorithm should be written as (using numpy.arange):

mytimes = numpy.arange(0, maxtime, 0.05)

Alternatively, with a generator:

def calcTimes(maxtime):
  dt = 0.05
  t = 0
  while t < maxtime:
   yield t
   t += dt
phihag
  • 278,196
  • 72
  • 453
  • 469
  • I disagree that while loops should only be used if it's impossible to iterate directly over something. (I've posted an example where I think the use of `while` is more clear than the use of an equivalent `for` loop.) – mgilson May 17 '12 at 14:12
  • @mgilson Amended the answer with a one-liner for your algorithm, and an equivalent generator. Note that a non-integer `range` is something you can easily implement in a [helper generator](http://stackoverflow.com/a/477610/35070). – phihag May 17 '12 at 14:18
  • 1
    I know about numpy.arange for these sorts of things -- but again, if you're writing a library, you don't necessarily want to force your users to download and install numpy just so you can do stuff like that. The generator function that you posted however is (I think) what I was looking for. Thanks. – mgilson May 17 '12 at 14:22