Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destructor in metaclass Singleton object

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 image 271
JoseLSegura Avatar asked Mar 10 '16 11:03

JoseLSegura


People also ask

Do Singleton classes have a destructor?

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.

How does Singleton destroy a singleton object?

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.

Why can't I delete inside the destructor of a class?

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...

How many instances of a singleton class can be created?

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.


1 Answers

Point 1: __del__() may not be called at process exit

The 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.

Point 2: predictable object lifetimes is an implementation detail in python

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.

Point 3: Singleton implementations generally maintain a global reference to the singleton instance

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.

What you could try

  1. Add an atexit handler when you create your singleton instance to do your necessary tidy up at process exit.
  2. Also do that tidy up in the __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.
    • And if you implement a __del__() method expecting to want tidy up to be done during normal program execution, you will probably want to remove the atexit handler too.
  3. If you would like your singleton to be cleaned up when no one is using it anymore, consider storing it on your metaclass using weakref so that you don't retain it yourself.
like image 131
daphtdazz Avatar answered Oct 25 '22 12:10

daphtdazz