Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroying a Singleton object in Python

I have a Singleton object in Python:

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

    @classmethod
    def destroy(cls):
        del cls._instances[cls]


class MockObject(metaclass=Singleton):

    def __init__(self, *args, **kwargs):
        # various things

I would like to destroy the object at some point, so I wrote a classmethod in the metaclass. However, the cls refers to the metaclass Singleton rather than MockObject. Is there a way to call the destroy function with a value of MockObject?

like image 437
user1742188 Avatar asked Apr 25 '17 19:04

user1742188


1 Answers

Instead of defining a custom method for deleting the instance reference use a WeakValueDictionary.

Now when there are no more references of MockObject anywhere it will be cleaned up from Singleton._instances automatically.

from weakref import WeakValueDictionary


class Singleton(type):
    _instances = WeakValueDictionary()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            # This variable declaration is required to force a
            # strong reference on the instance.
            instance = super(Singleton, cls).__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]


class MockObject(metaclass=Singleton):

    def __init__(self, *args, **kwargs):
        pass


if __name__ == '__main__':
    m = MockObject()
    print(dict(Singleton._instances))
    del m
    print(dict(Singleton._instances))

Output:

{<class '__main__.MockObject'>: <__main__.MockObject object at 0x104531128>}
{}
like image 171
Ashwini Chaudhary Avatar answered Sep 25 '22 06:09

Ashwini Chaudhary