我有一个带有单行
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")
它是 3.11 中引入的已知 CPython bug,并存在于 3.12 中。
在该错误的评论之一中,提到此拉取请求的部分向后移植看起来是修复该错误的正确方向。