How does for nested loop in python behave when range is the same for both outer and nested loop?

901 views Asked by At


Can you explain how the nested for loop behaves in figure 1?

x = 4
for j in range(x)
   for i in range(x)
       print(i)
       x = 2

Fig.1

Results

0
1
2
3
0
1
0
1
0
1

I know the first 4 integers printed ( 0 - 3) are a result of the code for j in range(x): code but why are the the following also printed?

0
1
0
1
0
1

The code

x = 4
for j in range(x):
    print(i)
    x = 5

Prints

0
1
2
3

Thus showing that changing the value x inside the for loop has no impact on the number of iterations. The arguments in the range function are evaluated just before the first iteration of the loop, and not reevaluated for subsequent iterations.

Why then does x change to 2 for the nested loop in figure 1?

Another similar program:

num_list = [1, 2, 3]
alpha_list = ['a', 'b', 'c']

for number in num_list:
    print(number)
    for letter in alpha_list:
        print(letter)

Outputs

1 #outer loop
a #nested loop
b #nested loop
c #nested loop
2 #outer loop
a #nested loop
b #nested loop
c #nested loop
3 #outer loop
a #nested loop
b #nested loop
c #nested loop

So I would expect figure 1's output to be:

0 #outer loop
0 #Nested loop
1 #Nested loop
2 #Nested loop
3 #Nested loop
1 #outer loop
0 #Nested loop
1 #Nested loop
2 #Nested loop
3 #Nested loop
2 #outer loop
0 #Nested loop
1 #Nested loop
2 #Nested loop
3 #Nested loop
3 #outer loop
0 #Nested loop
1 #Nested loop
2 #Nested loop
3 #Nested loop

Additional Info Python 3.5 in Spyder

6

There are 6 answers

0
currand60 On

Add some debug code to see what's going on to make it clearer

    loops = 1
    x = 4
    for j in range(x):
        print(f'outer: j={j}, x={x}')
        for i in range(x):
           print(f'inner: j={j}, i={i}, x={x}')
           print(i)
           x = 2
           print(f'total loops {loops}')
           loops += 1

Output:


    outer: j=0, x=4
    inner: j=0, i=0, x=4
    0
    total loops 1
    inner: j=0, i=1, x=2
    1
    total loops 2
    inner: j=0, i=2, x=2
    2
    total loops 3
    inner: j=0, i=3, x=2
    3
    total loops 4
    outer: j=1, x=2
    inner: j=1, i=0, x=2
    0
    total loops 5
    inner: j=1, i=1, x=2
    1
    total loops 6
    outer: j=2, x=2
    inner: j=2, i=0, x=2
    0
    total loops 7
    inner: j=2, i=1, x=2
    1
    total loops 8
    outer: j=3, x=2
    inner: j=3, i=0, x=2
    0
    total loops 9
    inner: j=3, i=1, x=2
    1
    total loops 10

It's easy to see that setting x once the range is constructed has no affect on the number of outer loop iterations but does change the number of inner loop iterations.

0
Joel S On

[enter image description here][1]

x = 4
for j in range(x):
    print(i)
    x = 5

output

0
1
2
3

Notice that the program above raise the question whether the value of x affects the number of iterations. It does not. The arguments to the range function in the line with for are evaluated just before the first iteration

So:

x = 4
for j in range(x)
   for i in range(x)
       print(i)
       x = 2
#Outputs
0   #j=0,
1   #j=0 
2    #j=0 
3    #j=0 
0    
1
0
1
0
1

This is because the range function in the outer loop is evaluated only once but the range function in the inner loop is evaluated each time the inner for statment is reached.

Note: for the outer loop the range is evaluated before the first iteration and the first iteration the inner for loop x=4. At the end of the first iteration of the outer for loop the inner for loop x =2 as the inner loop cannot see the initial x value.

Here is a flow chart that I thought helped me understand

https://www.programtopia.net/sites/default/files/nested%20for_1.png

0
Paul M. On

Thus showing that changing the value x inside the for loop has no impact on the number of iterations. The arguments in the range function are evaluated just before the first iteration of the loop, and not reevaluated for subsequent iterations.

Why then does x change to 2 for the nested loop in figure 1?

Not exactly. In your first example, with the nested for-loop, it does have an impact on the number of iterations. It's true that once a range object is constructed, making changes to any of the variables you used to construct it will have no effect on the range object - however, in the nested loop, you aren't just creating two range objects. You are creating one for the outer loop, and then a new range object for the inner for-loop for each iteration of the outer loop.

0
Mig B On

You are changing the value of x inside your second if-statement.

Your first if let's you run the second if 4 times. After printing 0 1 2 3once, your x is set to 2, giving you another 3 times 0 1.

As the first if-range iterator is already running, the changing x isn't influenced. Better don't change the variable, you are looping though.

0
Nikhil Gupta On

This is due to the scope of the variables. The x that is inside the inner 'for' loop with variable 'i' is given preference within the inner 'for' loop. This variable x is not visible outside the inner 'for' loop and so when you reference x in the outer 'for' loop (with variable 'j'), it references the global value of 4 and not 2.

Hope that makes sense.

Just my 2 cents -- This is not a very good coding practice, try to avoid (if possible) and use distinct variable names.

0
Masood Khaari On

Maybe the following code could explain it.

Your first code is identical to this:

x = 4
gen1 = range(x)  # effectively equal to range(4)

for j in gen1:
   gen2 = range(x)  # For the first time, this is equal to range(4).
                    # And for the following three times, this is equal to range(2).
   for i in gen2:
       print(i)
       x = 2

Note that range(x) creates and returns a generator object which is not altered by changing x afterwards. But you are creating a whole new generator object on the line gen2 = range(x) everytime, with a new value of x.