【问题标题】:How does the Python for loop actually work?Python for 循环实际上是如何工作的?
【发布时间】:2019-06-20 14:57:22
【问题描述】:

我很想了解 Python for 循环是如何在后台工作的。我试着实现它有点像下面的代码sn-p,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

【问题讨论】:

    标签: python for-loop python-internals


    【解决方案1】:

    是的,这是对 for 循环构造实现方式的一个很好的近似。它当然匹配for loop statement documentation:

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

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

    Python 源代码被编译成字节码,然后解释器循环执行。您可以使用dis module 查看for 循环的字节码:

    >>> 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 标志着 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 设置的块簿记,并从堆栈中删除迭代器。

    >> 标记是跳转目标,作为视觉提示,在读取跳转到它们的操作码行时更容易发现这些目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-07
      • 1970-01-01
      • 1970-01-01
      • 2022-07-07
      • 2011-10-28
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      相关资源
      最近更新 更多