I'm modifying a legacy library that uses the singleton pattern through the metaclass approach.
The Singleton class, inheriting from type
, defines de __call__
function.
Right now, my singleton object using this library are never deleted. I defined the __del__
method in the singleton classes and that function is never called.
Clarification: I have implemented one (meta)class named Singleton
, that is used by several classes, using Singleton
as __metaclass__
.
For example, I have class A(object)
, that has __metaclass__ = Singleton
. The A class has several members that I want to be destroyed when my program ends and the A object (the only one that can exist) is destroyed.
I tried defining __del__
method in A
class, but it doesn't work.
Like any self-respecting class, a Singleton class should define a destructor. If Singleton is to be subclassed, then the destructor should be declared virtual. All just C++ 101.
If and when the user first calls Singleton::Instance, not only will the Singleton object get created, but Instance will also pass that object to the static SingletonDestroyer object, effectively transferring ownership to the SingletonDestroyer. When the program exits, the SingletonDestroyer will be destroyed, and the Singleton object with it.
The problem is that you never call the destructor or delete on the instance pointer by hand, i.e. from outside the class. So the delete inside the destructor will never get executed, meaning the destructor will never get executed, meaning the delete will never get executed, meaning...
In the vanilla version of the pattern, Instance limits you to exactly one instance of the Singleton class (the User class in this case). But one of the pattern's consequences is the option to *control* the number of instances, as opposed to flatly precluding more than one.
__del__()
may not be called at process exitThe first thing to say is that
It is not guaranteed that
__del__()
methods are called for objects that still exist when the interpreter exits.
From the python data model docs. Therefore you should not be relying on it to tidy up state that you need to tidy up at exit, and at the highest level, that's why your __del__()
may not be being called. That's what atexit
is for.
The next thing to say is that while CPython uses reference counting to enable it to detect that an object can be released without having to use the garbage collector (leading to more predictable CPU impact and potentially more efficient applications), it only takes one circular reference, one uncleared exception, one forgotten closure or one different python implementation to break, and so you should think really really hard about whether you want to rely on __del__()
being called at a particular point.
By the sound of it, I would guess your singleton metaclass (itself a singleton...) is retaining your singleton instance the first time __call__()
is called. Since the metaclass is not released since it belongs to the module, which is itself retained by sys.modules
, that reference is not going to go away by the time the program terminates, so even given a guaranteed prompt tidy up of all external references to the singleton being freed, your __del__()
is not going to get called.
atexit
handler when you create your singleton instance to do your necessary tidy up at process exit.__del__()
method if you want. E.g, you may decide for neatness / future extensibility (e.g. pluralizing the singleton) that you would like the singleton instance to tidy up after itself when it is no longer being used.
__del__()
method expecting to want tidy up to be done during normal program execution, you will probably want to remove the atexit
handler too.weakref
so that you don't retain it yourself.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With