Python for循环实际上是如何工作的? [英] How does the Python for loop actually work?

查看:89
本文介绍了Python for循环实际上是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很想了解Python for 循环是如何在后台运行的.我试着像下面的代码片段那样实现它,就是for循环是如何实现的?

I am curious to understand how Python for loops work under the hood. I tried to implement it somewhat like the following code snippet, is that how the for loop has been implemented?

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 循环语句匹配文档:

Yes, that's a good approximation of how the for loop construct is implemented. It certainly matches the for loop statement documentation:

表达式列表只计算一次;它应该产生一个可迭代的对象.为 expression_list 的结果创建一个迭代器.然后,按照迭代器返回的顺序,对迭代器提供的每个项目执行一次套件.依次使用分配的标准规则将每个项目分配给目标列表(请参见分配语句),然后执行套件.当项目用尽时(即序列为空或迭代器引发 StopIteration 异常时),将执行 else 子句中的套件(如果存在),然后循环终止.

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 a StopIteration exception), the suite in the else clause, if present, is executed, and the loop terminates.

您仅错过了使用标准分配规则分配给目标列表的 部分;您必须使用 i = next(iter_list) print(i),而不是直接打印 next()调用的结果

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源代码被编译为 bytecode ,然后由解释器循环执行.您可以使用 dis 模块:

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

在同一个 dis 模块中记录了各种命名的操作码,它们的实现可以在

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 标记 suite 的开始(语句块),因此解释器知道在 break 的情况下跳转到的位置,以及在发生以下情况时需要执行的清除操作异常或 return 语句;清理操作码位于该操作码之后的字节码的12个字节处(因此此处为 POP_BLOCK ).
  • LOAD_NAME 0(我的列表) 加载 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 设置的块簿记并从堆栈中删除迭代器.
  • SETUP_LOOP 12 marks the start of the suite, a block of statements, so the interpreter knows where to jump to in case of a break, and what cleanup needs to be done in case of an exception or return statement; the clean-up opcode is located 12 bytes of bytecode after this opcode (so POP_BLOCK here).
  • LOAD_NAME 0 (mylist) loads the mylist variable value, putting it on the top of the stack (TOS in opcode descriptions).
  • GET_ITER calls iter() on the object on the TOS, then replaces the TOS with the result.
  • FOR_ITER 4 calls next() on the TOS iterator. If that gives a result, then that's pushed to the TOS. If there is a StopIteration exception, then the iterator is removed from TOS, and 4 bytes of bytecode are skipped to the POP_BLOCK opcode.
  • STORE_NAME 1 takes the TOS and puts it in the named variable, here that's i.
  • JUMP_ABSOLUTE 6 marks the end of the loop body; it tells the interpreter to go back up to bytecode offset 6, to the FOR_ITER instruction above. If we did something interesting in the loop, then that would happen after STORE_NAME, before the JUMP_ABSOLUTE.
  • POP_BLOCK removes the block bookkeeping set up by SETUP_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.

这篇关于Python for循环实际上是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆