Reassigning the variable you're looping over has no effect because the variable isn't re-evaluated for every iteration. In fact, the loop internally loops over an iterator, not over your range object.
Basically if you have a loop like this:
seq = range(5)
for elem in seq:
seq = something_else
Python rewrites it to something like this:
seq = range(5)
loop_iter = iter(seq) # obtain an iterator
while True:
try:
elem = next(loop_iter) # get the next element from the iterator
except StopIteration:
break # the iterator is exhausted, end the loop
# execute the loop body
seq = something_else
The crucial aspect of this is that the loop has its own reference to iter(seq) stored in loop_iter, so naturally reassigning seq has no effect on the loop.
All of this is explained in the compound statement documentation:
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
The expression list is evaluated once; it should yield an iterable
object. An iterator is created for the result of the expression_list.
The suite is then executed once for each item provided by the
iterator, in the order returned by the iterator.
lsis alreadyrange(5)beforehand and it just iterates through this iterable no matter it changes inside the loop.