How To Ensure The __del__ Function Is Called On A Python Class As Is Commonly (but Incorrectly) Expected?
Solution 1:
If you understand all that, why not do it in the Pythonic way? Compare another class where cleanup is important: tempfile.TemporaryDirectory
.
with TemporaryDirectory() as tmp:
# ...
# tmp is deleted
def foo():
tmp = TemporaryDirectory()
foo()
# tmp is deleted
How do they do this? Here's the relevant bit:
import weakref
class Foo():
def __init__(self, name):
self.name = name
self._finalizer = weakref.finalize(self, self._cleanup, self.name)
print("%s reporting for duty!" % name)
@classmethod
def _cleanup(cls, name):
print("%s feels forgotten! Bye!" % name)
def cleanup(self):
if self._finalizer.detach():
print("%s told to go away! Bye!" % self.name)
def foo():
print("Calling Arnold")
tmpfoo = Foo("Arnold")
print("Finishing with Arnold")
foo()
# => Calling Arnold
# => Arnold reporting for duty
# => Finishing with Arnold
# => Arnold feels forgotten. Bye!
def bar():
print("Calling Rocky")
tmpbar = Foo("Rocky")
tmpbar.cleanup()
print("Finishing with Rocky")
bar()
# => Calling Rocky
# => Rocky reporting for duty!
# => Rocky told to go away! Bye!
# => Finishing with Rocky
weakref.finalize
will trigger _cleanup
when the object is garbage-collected, or at the end of the program if it's still around. We can keep the finaliser around so that we can explicitly kill the object (using detach
) and mark it as dead so the finaliser is not called (when we want to manually handle the cleanup).
If you want to support the context usage with with
, it is trivial to add __enter__
and __exit__
methods, just invoke cleanup
in __exit__
("manual cleanup" as discussed above).
Solution 2:
This is a pattern I have been employing that achieves this using the atexit python module.
class Demo(object):
def __init__(self, *args, **kwargs):
import atexit
atexit.register(self.__del__)
def __del__(self):
print("__del__ being called!")
t1 = Demo()
t2 = Demo()
quit()
When pasted into a python command prompt, this is the total output:
Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> class Demo(object):
... def __init__(self, *args, **kwargs):
... import atexit
... atexit.register(self.__del__)
...
... def __del__(self):
... print("__del__ being called!")
...
>>> t1 = Demo()
>>> t2 = Demo()
>>>
>>> quit()
__del__ being called!
__del__ being called!
Post a Comment for "How To Ensure The __del__ Function Is Called On A Python Class As Is Commonly (but Incorrectly) Expected?"