I have been thinking about how I write classes in Python. More specifically how the constructor is implemented and how the object should be destroyed. I don\'t want to rely
Not necessarily. You'll encounter problems when you have cyclic references. Eli Bendersky does a good job of explaining this in his blog post:
If you are sure you will not go into cyclic references, then using __del__
in that way is OK: as soon as the reference count goes to zero, the CPython VM will call that method and destroy the object.
If you plan to use cyclic references - please think it very thoroughly, and check if weak references may help; in many cases, cyclic references are a first symptom of bad design.
If you have no control on the way your object is going to be used, then using __del__
may not be safe.
If you plan to use JPython or IronPython, __del__
is unreliable at all, because final object destruction will happen at garbage collection, and that's something you cannot control.
In sum, in my opinion, __del__
is usually perfectly safe and good; however, in many situation it could be better to make a step back, and try to look at the problem from a different perspective; a good use of try/except and of with contexts may be a more pythonic solution.
Short answer : No.
Long answer: Using __del__
is tricky, mainly because it's not guaranteed to be called. That means you can't do things there that absolutely has to be done. This in turn means that __del__
basically only can be used for cleanups that would happen sooner or later anyway, like cleaning up resources that would be cleaned up when the process exits, so it doesn't matter if __del__
doesn't get called. Of course, these are also generally the same things Python will do for you. So that kinda makes __del__
useless.
Also, __del__
gets called when Python garbage collects, and you didn't want to wait for Pythons garbage collecting, which means you can't use __del__
anyway.
So, don't use __del__
. Use __enter__/__exit__
instead.
FYI: Here is an example of a non-circular situation where the destructor did not get called:
class A(object):
def __init__(self):
print('Constructing A')
def __del__(self):
print('Destructing A')
class B(object):
a = A()
OK, so it's a class attribute. Evidently that's a special case. But it just goes to show that making sure __del__
gets called isn't straightforward. I'm pretty sure I've seen more non-circular situations where __del__
isn't called.