How Does The Python For Loop Actually Work?
Solution 1:
Yes, that's a good approximation of how the for
loop construct is implemented. It certainly matches the for
loop statement documentation:
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. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed. When the items are exhausted (which is immediately when the sequence is empty or an iterator raises aStopIteration
exception), the suite in theelse
clause, if present, is executed, and the loop terminates.
You only missed the assigned to the target list using the standard rules for assignments part; you'd have to use i = next(iter_list)
and print(i)
rather than print the result of the next()
call directly.
Python source code is compiled to bytecode, which the interpreter loop then executes. You can look at the bytecode for a for
loop by using the dis
module:
>>>import dis>>>dis.dis('for i in mylist: pass')
1 0 SETUP_LOOP 12 (to 14)
2 LOAD_NAME 0 (mylist)
4 GET_ITER
>> 6 FOR_ITER 4 (to 12)
8 STORE_NAME 1 (i)
10 JUMP_ABSOLUTE 6
>> 12 POP_BLOCK
>> 14 LOAD_CONST 0 (None)
16 RETURN_VALUE
The various opcodes named are documented in the same dis
module, and their implementation can be found in the CPython evaluation loop (look for the TARGET(<opcode>)
switch targets); the above opcodes break down to:
SETUP_LOOP 12
marks the start of the suite, a block of statements, so the interpreter knows where to jump to in case of abreak
, and what cleanup needs to be done in case of an exception orreturn
statement; the clean-up opcode is located 12 bytes of bytecode after this opcode (soPOP_BLOCK
here).LOAD_NAME 0 (mylist)
loads themylist
variable value, putting it on the top of the stack (TOS in opcode descriptions).GET_ITER
callsiter()
on the object on the TOS, then replaces the TOS with the result.FOR_ITER 4
callsnext()
on the TOS iterator. If that gives a result, then that's pushed to the TOS. If there is aStopIteration
exception, then the iterator is removed from TOS, and 4 bytes of bytecode are skipped to thePOP_BLOCK
opcode.STORE_NAME 1
takes the TOS and puts it in the named variable, here that'si
.JUMP_ABSOLUTE 6
marks the end of the loop body; it tells the interpreter to go back up to bytecode offset 6, to theFOR_ITER
instruction above. If we did something interesting in the loop, then that would happen afterSTORE_NAME
, before theJUMP_ABSOLUTE
.POP_BLOCK
removes the block bookkeeping set up bySETUP_LOOP
and removes the iterator from the stack.
The >>
markers are jump targets, there as visual cues to make it easier to spot those when reading the opcode line that jumps to them.
Post a Comment for "How Does The Python For Loop Actually Work?"