11

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.

JoseLSegura
  • 3,830
  • 3
  • 20
  • 27
  • It might help to understand why you need to destroy a singleton at all. You only have one. (Right? You speak as if you have multiple singletons, which is confusing.) If you only have one, it would be unusual to need to destroy it. – senderle Mar 10 '16 at 12:05
  • You are right. I'm editing my question – JoseLSegura Mar 10 '16 at 18:36
  • @senderle, In some testing scenarios, it is beneficial to have create a fixture that cleans after itself, while in production only a single instance of that object make sense, and cleanup is typically not required. – Chen Levy Dec 11 '16 at 12:41

1 Answers1

9

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.
daphtdazz
  • 7,754
  • 34
  • 54