I'm trying to figure out how to correctly handle the deletion of an object when there is an error in a piece of code.
It seem that when there is an Exception raised the object is maintainded alive, while I need the object to be deleted. How do I release the object ?
with the following exemple code:
class A():
def __init__(self) -> None:
print(f"A[{id(self)}] created")
def __del__(self):
print(f"A[{id(self)}] deletted !!")
def foo(obj):
raise ValueError
when I run foo(A())
I obtain:
A[1813071794504] created
[... traceback ...]
ValueError:
but I have no deletion
when I run a = A(); del a
I obtain what I was expecting:
A[1813073658952] created
A[1813073658952] deletted !!
precision: I am running that code with py3.7 in the interactive window of VSCode (if that change anything)
This is because the exception keeps a traceback of the call stack frames and that can keep variables alive until the traceback itself is deleted. If you run from the python shell or other interactive tools, they likely keep the traceback alive for inspection until another exception occurs. Notice how calling foo(A())
again, causes the deletion as soon as the second exception happens.
>>> foo(A())
A[140015433609328] created
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
ValueError
>>> foo(A())
A[140015432558352] created
A[140015433609328] deletted !!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
ValueError
>>>
If you add an exception handler and run from the command line you can see the deletion as the try/except clause ends.
class A():
def __init__(self) -> None:
print(f"A[{id(self)}] created")
def __del__(self):
print(f"A[{id(self)}] deletted !!")
def foo(obj):
raise ValueError
try:
foo(A())
except ValueError:
print("handle exception")
print("exiting")
output
A[139771605026992] created
handle exception
A[139771605026992] deletted !!
exiting