我很想了解 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
循环语句文档:
表达式列表被评估一次;它应该产生一个可迭代的对象。为
的结果创建一个迭代器。然后,按照迭代器返回的顺序,为迭代器提供的每个项目执行一次该套件。使用标准分配规则(请参阅分配语句)将每个项目依次分配给目标列表,然后执行该套件。当项目耗尽时(即当序列为空或迭代器引发expression_list
异常时),StopIteration
子句中的套件(如果存在)将被执行,并且循环终止。else
您只错过了使用标准分配规则分配到目标列表部分;您必须使用
i = next(iter_list)
和 print(i)
而不是直接打印 next()
调用的结果。
Python 源代码被编译为 字节码,然后解释器循环执行。您可以使用
for
模块:查看
dis
循环的字节码
>>> 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 评估循环中找到(查找 TARGET(<opcode>)
开关目标);上述操作码分解为:
SETUP_LOOP 12
标记suite(一个语句块)的开始,因此解释器知道在出现 break
的情况下跳转到哪里,以及在发生异常或 的情况下需要进行哪些清理return
声明;清理操作码位于该操作码之后 12 个字节的字节码中(所以这里是 POP_BLOCK
)。LOAD_NAME 0 (mylist)
加载mylist
变量值,将其放在堆栈顶部(操作码描述中的TOS)。GET_ITER
对 TOS 上的对象调用 iter()
,然后用结果替换 TOS。FOR_ITER 4
在 TOS 迭代器上调用 next()
。如果给出结果,则会将其推送到 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
设置的块簿记,并从堆栈中删除迭代器。>>
标记是跳转目标,有视觉提示,可以在读取跳转到它们的操作码行时更容易发现它们。
作为 Martijn 已经说过的话的补充,在不使用
for
的情况下,最接近在 Python 中实现的 for
循环的方法是转换:
for x in mylist:
print(x)
对此:
NULL = object() # We don't have real NULL from C, but we can simulate it as a guaranteed unique object; avoids invoking exception machinery in common case
iter_obj = iter(iterable)
while (x := next(iter_obj, NULL)) is not NULL:
print(x)
与你猜测的主要区别是:
next
调用、名称赋值和循环结束检查之外的任何内容都不会包含在 try
块中(如果其他任何内容引发 StopIteration
,则它不会被 for
捕获)
循环机械)break
用于正常循环退出条件(如果 else:
块附加到 for
,则很重要;如果你 break
,则跳过它,如果正常退出,则调用它,两者都是真实的) for
循环和这个while
模拟)