我很想了解 Python for
循环在幕后是如何工作的。我尝试像下面的代码片段一样实现它,for循环就是这样实现的吗?
my_list = [1, 2, 3, 4, 5]
# list itself is iterable but not iterator. Make it an iterator
iter_list = iter(my_list)
while True:
try:
print(next(iter_list))
except StopIteration:
break
最佳答案
是的,这非常接近 for
循环构造被实现。它肯定符合 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.
您只错过了使用标准分配规则分配给目标列表部分;你必须使用i = next(iter_list)
和print(i)
而不是打印 next()
的结果直接打电话。
Python 源代码被编译为字节码,然后解释器循环执行。您可以查看字节码 for
使用 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
命名的各种操作码记录在同一个 dis
中模块,其实现可以在 CPython evaluation loop 中找到(查找 TARGET(<opcode>)
开关目标);上述操作码分解为:
-
SETUP_LOOP 12
标记套件(一个语句 block )的开始,因此解释器知道在出现break
时跳转到哪里,以及在出现异常或return
的情况下需要执行哪些清理操作陈述;清理操作码位于此操作码之后 12 个字节的字节码(因此POP_BLOCK
此处)。 -
LOAD_NAME 0 (mylist)
加载mylist
变量值,将其放在堆栈顶部(操作码描述中的 TOS)。 -
GET_ITER
来电iter()
TOS 上的对象,然后用结果替换 TOS。 -
FOR_ITER 4
来电next()
在 TOS 迭代器上。如果给出结果,则会将其推送到 TOS。如果有StopIteration
异常,则迭代器从 TOS 中删除,并且 4 个字节的字节码被跳到POP_BLOCK
操作码。 -
STORE_NAME 1
获取 TOS 并将其放入指定变量中,这里是i
. -
JUMP_ABSOLUTE 6
标记循环体的结束;它告诉解释器返回到字节码偏移 6,即FOR_ITER
上面的说明。如果我们在循环中做了一些有趣的事情,那么这将发生在STORE_NAME
之后,在JUMP_ABSOLUTE
之前. -
POP_BLOCK
删除SETUP_LOOP
设置的 block 记账并从堆栈中删除迭代器。
>>
标记是跳转目标,有视觉提示,可以在阅读跳转到它们的操作码行时更容易发现它们。
关于python - Python for 循环实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54387889/