What is the best approach to implement the opposite of __init__
so that users can type del obj
and expect that the deleted object is cleaned up properly?
Example:
import weakref
registry = weakref.WeakValueDictionary()
class myClass(object):
def __init__(self) -> None: # CREATOR
registry[id(self)] = self
def __destroy__(self): # DESTROYER
del registry[id(self)]
To make the case very explicit: My users expect that del obj
results in a clean database that sits on disk. I merely use registry
as a mock example hereof.
Test case:
a = myClass()
assert a in registry
del a # must trigger call to __destroy__
assert a not in registry
test case 2:
a = MyClass()
b = a
del a
assert b in registry
del b
assert len(registry) == 0
This problem is very well documented in [1, 2, 3, 4], but there does not seem to be any solution:
-
__del__
does not guarantee any action until garbage collection, and that wont happen immediately. -
atexit.register
is too late, as I want the program to react todel obj
-
I lack creativity to make a
context manager
s__enter__
&__exit__
work as the objects may have overlapping lifecycles (test case 2). -
Monking patching
del
is not possible asdel
is a reserved keyword. If anatexit
-type register existed I would be able to attach__terminate__
to thedel
keywork:
import keywords
keywords.register(del, myClass.__terminate__)
such that the behaviour would be:
def del(*args):
for arg in args:
if isinstance(arg, myClass):
arg.terminate()
keywords.del arg # let gc deal with the clean up
- The problem is not associated with cyclic references [4], but rather that
assert
s are executed straight afterdel
and that is too early for garbage collection.
[1] Python Gotchas 1: __del__ is not the opposite of __init__
[2] destructor - How do I correctly clean up a Python object? - Stack Overflow
[3] python - Opposite of __init__ in thread class? - Stack Overflow
[4] Safely using destructors in Python - Eli Bendersky's website