两行Python代码导致3个执行块

问题描述 投票:2回答:1

我正在试验Python操作码,很惊讶看到下面的dis.dis输出。给出以下两行:

[i for i in range(10)]
print("OK")

如您所见,这两行导致3个块。为什么第一个和第三个块属于第一行?是否也按此顺序执行?我希望从CC++编译器获得这样的乱序指令,但我不理解第三个代码块:

1           0 LOAD_CONST               0 (<code object <listcomp> at 0x109664540, file "example.py", line 1>)
            2 LOAD_CONST               1 ('<listcomp>')
            4 MAKE_FUNCTION            0
            6 LOAD_NAME                0 (range)
            8 LOAD_CONST               2 (10)
            10 CALL_FUNCTION            1
            12 GET_ITER
            14 CALL_FUNCTION            1
            16 POP_TOP

2          18 LOAD_NAME                1 (print)
            20 LOAD_CONST               3 ('OK')
            22 CALL_FUNCTION            1
            24 POP_TOP
            26 LOAD_CONST               4 (None)
            28 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x109664540, file "test", line 1>:
1           0 BUILD_LIST               0
            2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                 8 (to 14)
            6 STORE_FAST               1 (i)
            8 LOAD_FAST                1 (i)
            10 LIST_APPEND              2
            12 JUMP_ABSOLUTE            4
        >>   14 RETURN_VALUE

P.S。什么是>>?文档将它们描述为a labelled instruction, indicated with >>,,但我不能在上面的示例中应用此注释。

python python-3.x python-3.7
1个回答
0
投票

<listcomp>是解释器在取消列表理解时创建的单独对象。它用于隔离理解名称空间(循环变量i)并构建列表。首先创建它,然后经过一些准备后调用,最后将其丢弃。

您可以在开始时看到正在创建的帮助程序:

1           0 LOAD_CONST               0 (<code object <listcomp> at 0x109664540, file "example.py", line 1>)
            2 LOAD_CONST               1 ('<listcomp>')
            4 MAKE_FUNCTION            0

由于CPython是基于堆栈的VM,因此先前的指令可以在堆栈上放置用于后续指令的参数。在这里,您可以看到正在加载的代码对象(反汇编中的第三个块),正在加载的名称以及最后根据刚刚添加到堆栈中的内容创建的函数。请注意,您实际上可以看到此功能,例如如果理解中有错误,则会在回溯中显示。

接下来,Python在该范围内创建一个迭代器:

        6 LOAD_NAME                0 (range)
        8 LOAD_CONST               2 (10)
        10 CALL_FUNCTION            1
        12 GET_ITER

这将加载range函数及其参数,然后将其应用-我们现在在堆栈顶部有range(10)。最后,将范围删除,并用其迭代器替换。

最后,Python调用helper函数:

        14 CALL_FUNCTION            1

[请记住,我们的堆栈之前已经填充了辅助函数<listcomp>和范围迭代器。其他所有东西都从堆栈中消失了。因此,此处Python以范围迭代器作为参数调用了辅助函数。帮助程序返回列表理解产生的列表。


  • >>是什么?

它们是字节码执行中可能的跳转/分支的可视化。

例如,可以完成for循环(跳转到循环的结尾),也可以执行另一个项(跳转到循环的开始)。您可以在反汇编中看到此内容:

  >>    4 FOR_ITER                 8 (to 14)
        6 STORE_FAST               1 (i)
        8 LOAD_FAST                1 (i)
        10 LIST_APPEND              2
        12 JUMP_ABSOLUTE            4
   >>   14 RETURN_VALUE

指令4是循环的迭代(即在列表理解中)。它的参数(在右边)是块大小,即8。这意味着完成后,它会跳转to 14 —标有>>的返回指令。由于循环必须对每个项目重复,因此它的最后一条指令12是跳转到4处的循环指令-也标记为>>

© www.soinside.com 2019 - 2024. All rights reserved.