简体   繁体   中英

Reassigning value of iterator while iterating through it

First of all a disclaimer :

I don't want to use a code like this, I am aware it is a bad practice. As well I am not interested in tips on how to improve it, to make it right. What interests me is a theory.

How come code like this works in python 3.6:

ls = range(5)
for elem_a in ls:

    ls = range(5, 10)
    for elem_b in ls:
        print(elem_a, elem_b)

I am reassigning the value of ls while iterating through it. Is the value of ls in the first iteration stored in memory during the first execution of for elem_a in ls ?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM