I found this strange behavior. Why is the error variable not garbage collected? If error is another object, this wouldn't happen.
import gc import weakref class MyException(Exception): pass def func(): try: raise MyException() except MyException as exc: error = exc return error # Only for inspection import dis dis.dis(func) # Only keep a weak reference to the exception err = func() ref = weakref.ref(err) del err # Check if anything refers to the exception refs = gc.get_referrers(ref()) for ref_ in refs: if ref_.__class__.__name__ == "frame": print(ref_)The output with Python 3.12 is:
Output: 7 0 RESUME 0 8 2 NOP 9 4 LOAD_GLOBAL 1 (NULL + MyException) 14 CALL 0 22 RAISE_VARARGS 1 >> 24 PUSH_EXC_INFO 10 26 LOAD_GLOBAL 0 (MyException) 36 CHECK_EXC_MATCH 38 POP_JUMP_IF_FALSE 13 (to 66) 40 STORE_FAST 0 (exc) 11 42 LOAD_FAST 0 (exc) 44 STORE_FAST 1 (error) 46 POP_EXCEPT 48 LOAD_CONST 0 (None) 50 STORE_FAST 0 (exc) 52 DELETE_FAST 0 (exc) 12 54 LOAD_FAST 1 (error) 56 RETURN_VALUE >> 58 LOAD_CONST 0 (None) 60 STORE_FAST 0 (exc) 62 DELETE_FAST 0 (exc) 64 RERAISE 1 10 >> 66 RERAISE 0 >> 68 COPY 3 70 POP_EXCEPT 72 RERAISE 1 ExceptionTable: 4 to 22 -> 24 [0] 24 to 40 -> 68 [1] lasti 42 to 44 -> 58 [1] lasti 58 to 66 -> 68 [1] lasti <frame at 0x7f37f9f4d3c0, file '/home/XXX/test.py', line 12, code func> 