`dis`输出中的`ExceptionTable`是什么?

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

python3.13
中,当我尝试拆解
[i for i in range(10)]
时,结果如下:

>>> import dis
>>> 
>>> dis.dis('[i for i in range(10)]')
   0           RESUME                   0

   1           LOAD_NAME                0 (range)
               PUSH_NULL
               LOAD_CONST               0 (10)
               CALL                     1
               GET_ITER
               LOAD_FAST_AND_CLEAR      0 (i)
               SWAP                     2
       L1:     BUILD_LIST               0
               SWAP                     2
       L2:     FOR_ITER                 4 (to L3)
               STORE_FAST_LOAD_FAST     0 (i, i)
               LIST_APPEND              2
               JUMP_BACKWARD            6 (to L2)
       L3:     END_FOR
       L4:     SWAP                     2
               STORE_FAST               0 (i)
               RETURN_VALUE

  --   L5:     SWAP                     2
               POP_TOP

   1           SWAP                     2
               STORE_FAST               0 (i)
               RERAISE                  0
ExceptionTable:
  L1 to L4 -> L5 [2]

在输出的最后,有一些东西

ExceptionTable
。以前版本的python中不存在。

Python 3.10.0b1 (default, May  4 2021, 00:00:00) [GCC 10.2.1 20201125 (Red Hat 10.2.1-9)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dis
>>> 
>>> dis.dis('[i for i in range(10)]')
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x7f3d412503a0, file "<dis>", 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 RETURN_VALUE

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

我不明白这意味着什么,也找不到这方面的任何文档。

python-3.x cpython python-internals dis
1个回答
1
投票

ExceptionTable
确定引发异常时跳转到哪里,并在 中实现。之前的版本使用单独的操作码来处理这个问题。

这里有很好的记录。引用同一文档:

python-3.11

使用所谓的“”异常处理。 在 python-3.11 之前,异常是由运行时的“块”堆栈处理的。在零成本异常处理中,支持异常的成本为 最小化。在一般情况下(没有例外)成本 减少到零(或接近于零)。筹集资金的成本 例外情况有所增加,但幅度不大。

以下代码:

def f(): try: g(0) except: return "fail" compiles as follows in 3.10: 2 0 SETUP_FINALLY 7 (to 16) 3 2 LOAD_GLOBAL 0 (g) 4 LOAD_CONST 1 (0) 6 CALL_NO_KW 1 8 POP_TOP 10 POP_BLOCK 12 LOAD_CONST 0 (None) 14 RETURN_VALUE 4 >> 16 POP_TOP 18 POP_TOP 20 POP_TOP 5 22 POP_EXCEPT 24 LOAD_CONST 3 ('fail') 26 RETURN_VALUE

注意从“块”堆栈中压入和弹出的显式指令:
SETUP_FINALLY

POP_BLOCK
在 3.11 中,

SETUP_FINALLY

POP_BLOCK
被删除,替换为
用于确定引发异常时跳转到何处的表
1 0 RESUME 0 2 2 NOP 3 4 LOAD_GLOBAL 1 (g + NULL) 16 LOAD_CONST 1 (0) 18 PRECALL 1 22 CALL 1 32 POP_TOP 34 LOAD_CONST 0 (None) 36 RETURN_VALUE >> 38 PUSH_EXC_INFO 4 40 POP_TOP 5 42 POP_EXCEPT 44 LOAD_CONST 2 ('fail') 46 RETURN_VALUE >> 48 COPY 3 50 POP_EXCEPT 52 RERAISE 1 ExceptionTable: 4 to 32 -> 38 [0] 38 to 40 -> 48 [1] lasti

(注意此代码来自
python-3.11

,以后的版本可能略有 不同的字节码。)如果指令引发异常,则使用其偏移量来查找 要跳转到的目标。例如,偏移量 22 处的

CALL

属于 范围 4 到 32。因此,如果

g()
引发异常,则控制跳转 偏移 38。

    

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