I have a code with a one-liner while and a try-except statement which behaves weirdly.
This prints 'a' on Ctrl+C:
try: while True: passexcept KeyboardInterrupt: print("a")and this too:
try: i = 0 while True: passexcept KeyboardInterrupt: print("a")but this doesn't, and it throws a traceback:
try: while True: passexcept KeyboardInterrupt: print("a")and neither does this code:
try: while True: pass i = 0except KeyboardInterrupt: print("a")Addition some additional details.
In 3.11, the instruction JUMP_BACKWARD was added and seems invloved with this issue see: Disassembler for Python bytecode
In 3.12 when the code in the first and the 3rd blocks are disassembled the results are:
Cannot be caught:
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 1ExceptionTable: 4 to 4 -> 6 [0] 6 to 30 -> 38 [1] lasti 36 to 36 -> 38 [1] lastiNoneCan be caught:
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 1ExceptionTable: 4 to 8 -> 10 [0] 10 to 34 -> 42 [1] lasti 40 to 40 -> 42 [1] lastiNoneThe main differences that jump out are the two additional NOP and the different targets for JUMP_BACKWARD.
Note: the exception really cannot be caught as this will also throw the exception in 3.12
try: try: while True: pass except KeyboardInterrupt: print("a")except Exception: print("b")