For loop emits integers 1, 2, 3, 4. While loop runs if integer value is less than three i.e. 1 and 2. While loop executes twice on 1 (1, 2) and once on 2.
Last i value in for-loop is 4 and therefore it printed at the end.
If your confusion stems from the fact that the inner loop manipulates i and the outer loop’s next iteration doesn’t then “jump” to that future state, the while loop isn’t actually relevant. For example:
for i in range(5):
print(f"before modifying: {i}")
i = 0
print(f"after modifying: {i}")
will print out:
before modifying: 0
after modifying: 0
before modifying: 1
after modifying: 0
before modifying: 2
after modifying: 0
before modifying: 3
after modifying: 0
before modifying: 4
after modifying: 0
It doesn’t get stuck in an infinite loop at 1 forever as you might expect (because you set it to zero and then it gets incremented). The for loop’s iterator’s state isn’t stored in your local variable.
When you nest loops, the complete inner loop happens again, each time that the outer loop runs.
Where the code says for i in range(1,5):, the range(1,5) part is not part of some special syntax for the for loop. rangeis not a keyword; it’s the name of a type - just like int and str and list. This code creates an object that represents some numbers, and then the for loop uses those numbers in sequence.
You can use a for loop with anything that is iterable - i.e., that represents multiple (zero or more) values that can be accessed in order, one at a time. For example, you can use a string (you get one character each time), or a text file that was opened for reading (you get one line of text from the file at a time), or a dict (you get each of its keys).
A for loop sets the value of its tracking variable, using the values from its element source. In this case, the source is range(1, 5), which contains four values: 1, 2, 3 and 4. So the for loop will run 4 times. It does not care about any change that is made to i, by any of the code inside the loop. It simply sets the value at the top of the loop, according to what it accesses from its source, in order, one at a time.
Only an abnormal exit (break, return, or raising an exception) or a modification to the element source (not possible here; range objects are immutable) can make the loop run a different number of times. At the beginning of the first time through the for loop, i is set to 1. At the beginning of the second time through, it is set to 2, regardless of anything that happened the first time through.
The first time through the for loop, i was set to 1. So the while loop will check that i < 3, and print the messages for a value of 1. It increments i to 2, which is still less than 3, so it runs one more time. (The print(i) inside the while loop cannot happen, because continue skips it.) After the while loop, the for loop does pass, which has no effect (by definition). This is the first time that 2 in w appears.
The second time through the for loop, i was set to 2. So the while loop will check that i < 3, and print the messages for a value of 2. It increments i to 3, so it can’t run again. This is the second time that 2 in w appears.
The third and fourth times through the for loop, the i value does not allow the while loop to be entered at all.
Because that is the value it has after the for loop has completed. The last time that the for loop runs, it sets i to 4. The while loop does not run, because 4 is not less than 3, so there is no code that can change the value of i after that.