旧版 Python 中 END_FINALLY 字节码的用途是什么?

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

考虑以下代码:

try:
    helloworld()
except:
    failure()

及其反汇编(这是在Python 2.7中):

  1           0 SETUP_EXCEPT            11 (to 14)

  2           3 LOAD_NAME                0 (helloworld)
              6 CALL_FUNCTION            0
              9 POP_TOP             
             10 POP_BLOCK           
             11 JUMP_FORWARD            14 (to 28)

  3     >>   14 POP_TOP             
             15 POP_TOP             
             16 POP_TOP             

  4          17 LOAD_NAME                1 (failure)
             20 CALL_FUNCTION            0
             23 POP_TOP             
             24 JUMP_FORWARD             1 (to 28)
             27 END_FINALLY         
        >>   28 LOAD_CONST               0 (None)
             31 RETURN_VALUE     

假设

helloworld()
引发异常,则代码从地址 14 开始。因为这个 except 处理程序是通用的,所以后面跟着三个 POP_TOP 和
failure()
函数调用是有意义的。然而,之后,有一个
24 JUMP_FORWARD
“跳过”
27 END_FINALLY
,因此它不会被执行。它在这里的目的是什么?

我注意到版本 3.5、3.6、3.7 和 3.8 中也有类似的行为。在 3.9 中,它似乎被重命名为 RERAISE:https://godbolt.org/z/YbeqPf3nx

一些上下文:在简化了混淆的 pyc 和大量调试之后,我发现这样的结构被破坏了

uncompyle6

python python-2.7 bytecode cpython
1个回答
0
投票

finally
块结束时,或者没有
finally
块并且没有
except
块匹配时,它会恢复异常的传播。它还可以处理恢复被
return
块暂停的
continue
finally

但是你没有

finally
,而你有一条毯子
except
,它 always 匹配,所以
END_FINALLY
永远不会运行。它可以被消除,但字节码编译器中没有处理这样做。

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