Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python nested for loop behaviour

I came across this weird behaviour with nested for loops and I can't for the light of me explain this. Is this a python-specific thing or am I just overseeing something?

This is the code I'm running:

for i in range(16):
    if i == 0:
        for j in range(8):
            print 'i is (if) ' + str(i)
            i = i + 1
    else:
        print 'i is (else)' + str(i)

This is the output I'm getting:

i is (if) 0
i is (if) 1
i is (if) 2
i is (if) 3
i is (if) 4
i is (if) 5
i is (if) 6
i is (if) 7
i is (else)1
i is (else)2
i is (else)3
i is (else)4
i is (else)5
i is (else)6
i is (else)7
i is (else)8
i is (else)9
i is (else)10
i is (else)11
i is (else)12
i is (else)13
i is (else)14
i is (else)15

This is the output I'm expecting:

i is (if) 0
i is (if) 1
i is (if) 2
i is (if) 3
i is (if) 4
i is (if) 5
i is (if) 6
i is (if) 7
i is (else)8
i is (else)9
i is (else)10
i is (else)11
i is (else)12
i is (else)13
i is (else)14
i is (else)15

It seems like the i in the outer for loop and the i in the inner for loop are different variables, although that seems completely counterintuitive to me.

Any input (I'm fairly new to python but couldn't find documentation on this)

like image 863
kbroos Avatar asked Jan 13 '23 17:01

kbroos


1 Answers

The for loop assigns a new value to i every loop iteration, namely the next value taken from the loop iterable (in this case range(16).

You can modify i in the loop itself, but that doesn't alter the iterable for is working with.

If you wanted to change the loop iterable, then you'd have to do so directly on the iterable:

loop_iterable = iter(range(16))
for i in loop_iterable:
    if i == 0:
        for j in range(8):
            print 'i is (if) ' + str(i)
            i = next(loop_iterable)
    else:
        print 'i is (else)' + str(i)

Here, we create a iterator object from the range(10) sequence by using the iter() function; the for statement does the exact same thing under the hood, but now we can address the iterator directly. The next() function advances the iterator to the next value, just like the for loop would do.

However, it may be easier to just use a while loop instead:

i = 0
while i < 16:
    if i == 0:
        for j in range(8):
            print 'i is (if) ' + str(i)
            i = next(loop_iterable)
    else:
        print 'i is (else)' + str(i)
    i += 1

The thing to remember is that the Python for loop statement is nothing like a C or Java or JavaScript for loop. It is a Foreach loop instead. range() simply generates a sequence of numbers to loop over, as opposed to a C-style for loop, which combines the initial assignment (i = 0), test (i < 16)) and loop incrementer (i += 1) into one statement.

like image 63
Martijn Pieters Avatar answered Jan 22 '23 09:01

Martijn Pieters