为什么单行 while 语句不能捕获异常?

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

我有一个带有单行

while
try
-
except
语句的代码,其行为很奇怪。

这会在 Ctrl+C 上打印“a”:

try:
    while True:
        pass
except KeyboardInterrupt:
    print("a")

还有这个:

try:
    i = 0
    while True: pass
except KeyboardInterrupt:
    print("a")

但这不是,它会引发回溯:

try:
    while True: pass
except KeyboardInterrupt:
    print("a")

这段代码也没有:

try:
    while True: pass
    i = 0
except KeyboardInterrupt:
    print("a")

添加一些额外的细节。

在 3.11 中,添加了指令

JUMP_BACKWARD
,似乎与此问题有关,请参阅:Python 字节码反汇编器

在3.12中,当第一块和第三块中的代码被反汇编时,结果是:

无法被抓住:

  0           0 RESUME                   0

  2           2 NOP

  3     >>    4 JUMP_BACKWARD            1 (to 4)
        >>    6 PUSH_EXC_INFO

  4           8 LOAD_NAME                0 (KeyboardInterrupt)
             10 CHECK_EXC_MATCH
             12 POP_JUMP_IF_FALSE       11 (to 36)
             14 POP_TOP

  5          16 PUSH_NULL
             18 LOAD_NAME                1 (print)
             20 LOAD_CONST               1 ('a')
             22 CALL                     1
             30 POP_TOP
             32 POP_EXCEPT
             34 RETURN_CONST             2 (None)

  4     >>   36 RERAISE                  0
        >>   38 COPY                     3
             40 POP_EXCEPT
             42 RERAISE                  1
ExceptionTable:
  4 to 4 -> 6 [0]
  6 to 30 -> 38 [1] lasti
  36 to 36 -> 38 [1] lasti
None

可捕捉:

  0           0 RESUME                   0

  2           2 NOP

  3           4 NOP

  4     >>    6 NOP

  3           8 JUMP_BACKWARD            2 (to 6)
        >>   10 PUSH_EXC_INFO

  5          12 LOAD_NAME                0 (KeyboardInterrupt)
             14 CHECK_EXC_MATCH
             16 POP_JUMP_IF_FALSE       11 (to 40)
             18 POP_TOP

  6          20 PUSH_NULL
             22 LOAD_NAME                1 (print)
             24 LOAD_CONST               1 ('a')
             26 CALL                     1
             34 POP_TOP
             36 POP_EXCEPT
             38 RETURN_CONST             2 (None)

  5     >>   40 RERAISE                  0
        >>   42 COPY                     3
             44 POP_EXCEPT
             46 RERAISE                  1
ExceptionTable:
  4 to 8 -> 10 [0]
  10 to 34 -> 42 [1] lasti
  40 to 40 -> 42 [1] lasti
None

跳出的主要区别是两个额外的

NOP
以及
JUMP_BACKWARD
的不同目标。

注意:异常确实无法被捕获,因为这也会在3.12中抛出异常

try:
    try:
        while True: pass
    except KeyboardInterrupt:
        print("a")
except Exception:
    print("b")
python try-catch
1个回答
0
投票

它是 3.11 中引入的已知 CPython bug,并存在于 3.12 中。

在该错误的评论之一中,提到此拉取请求的部分向后移植看起来是修复该错误的正确方向。

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