JoseLSegura
JoseLSegura

Reputation: 3890

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.

Upvotes: 11

Views: 2649

Answers (1)

daphtdazz
daphtdazz

Reputation: 8159

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.

Upvotes: 9

Related Questions