3

I noticed that in Python it is possible to mimic while-loops using for-loops (I know very little about coding). I was then trying to construct two identical while-loops using the two different formulations. It seems to me that it is the case here (is it?)

# for-loop formulation
index = [0]
for a in index:
    if a < 6:
       index.append(a + 1) 

# while-loop formulation
index = [0]
while index[-1] < 6:
    index.append(index[-1] + 1)

What confuses me is that I thought that once the list index is updated/changed the for-loop would restart from the beginning, as the list could have changed dramatically at any cycle. For example if you run

#3
index = [0]
for a in index:
    print a
    if a < 6:
       index.append(a+1)
       if a > 3:
           index = [1, 3]
    print index

you get the output

0
[0, 1]
1
[0, 1, 2]
2
[0, 1, 2, 3]
3
[0, 1, 2, 3, 4]
4
[1, 3]
5
[1, 3]

where the a is not part of the new index [1, 3] in the last step. Hence three questions:

  1. Are the two programs #1 and #2 at the beginning different (for example, is their computational effort different?)
  2. What is happening in program #3 (why is the 'for a in index:' command apparently ignored in the last step?), and how does the for-loop react to changes in the updating index in general?
  3. Are there general guidelines on using for loops as while loops (I noticed that I found it helpful in a specific case, so I was wondering for some general tips in this direction).
Rgkpdx
  • 257
  • 1
  • 9
  • Are you more interested in a python answer or a "general" answer? – syntonym Feb 14 '18 at 01:10
  • 2
    The behaviour isn’t well-documented in Python (there’s [a vague note about it](https://docs.python.org/3.7/reference/compound_stmts.html#the-for-statement) and that’s all; discussion at https://bugs.python.org/issue32767) and relying on it will confuse people reading your code. Go with the more explicit `while` loop. – Ry- Feb 14 '18 at 01:12
  • 5
    Ideally, you should not modify the size of the collection being iterated over. The while loop just checks the last value of the list, not iterates over the content – OneCricketeer Feb 14 '18 at 01:13
  • 1
    agree with @cricket_007: for-loop and while-loop are different. If you will disassemble code you will see that for-loop setups iterator, while while-loop do not. Create functions for each loop and disassemble them with [`dis`](https://docs.python.org/2/library/dis.html) module. – sKwa Feb 14 '18 at 01:17
  • "What confuses me is that I thought that once the list index is updated/changed the for-loop would restart from the beginning" it does not. – juanpa.arrivillaga Feb 14 '18 at 01:21
  • @syntonym: kind of both, maybe a bit more interested in a python answer. – Rgkpdx Feb 14 '18 at 01:21
  • @sKwa: can you refer to the code I wrote if possible? (That would make it more clear to me) – Rgkpdx Feb 14 '18 at 01:27
  • [Worth reading](https://stackoverflow.com/q/1207406/364696), since what you're doing will inevitably lead to other invalid uses of iterators. – ShadowRanger Feb 14 '18 at 01:52

1 Answers1

1

The first two are basically the same, in that they will run the same number of iterations under various circumstances, and will leave index in the same state. If you replace index.append(a+1) with index.append(a), the for loop will run forever; similarly, if you replace index.append(index[-1] + 1) with index.append(index[-1]), the while loop will run forever. It's a bit fraught to modify a list you're iterating over like this, but it's sometimes a reasonable tactic.

What's happening with the for loop, by the way, is that when you start it, an iterator is created that gives index[0], then index[1], then index[2], etc., until it gets to an index[N] that doesn't exist. This iterator doesn't know or care that you're changing the list, so if you make the list longer, it will happily go on longer.

In program #3, there's some confusion of scoping. The iterator that's created when you enter the for loop doesn't care that you're reassigning the variable index inside the for loop: it just keeps iterating over the original list. When you do index.append(a+1) the first few times, that does affect the original list; but as soon as you do index = [1, 3], index no longer refers to the original list, so nothing you do to it affects the remaining course of the iteration. The last value that gets added is 5, because once a gets to 4 and a+1 is appended to index, index is clobbered and nothing more gets appended to the original list.

Lastly, the clobbering of index persists outside the for loop: it will have the value [1, 3] when the loop is done.

Nathan Vērzemnieks
  • 5,495
  • 1
  • 11
  • 23