There are many methods to implement the singleton mode in Python. I personally think the decorator-based method is the most elegant.
Find an implementation from stackoverflow. I changed it to thread-safe, and the record is as follows:
import threadingclass Singleton: """ A class to ease implementing singletons. This should be used as a decorator -- not a metaclass -- to the class that should be a singleton. The decorated class can define one `__init__` function that takes only the `self` argument. Other than that, there are no restrictions that apply to the decorated class. To get the singleton instance, use the `Instance` method. Trying to use `__call__` will result in a `TypeError` being raised. Limitations: The decorated class cannot be inherited from. """ def __init__(self, decorated): self._decorated = decorated self.lock = threading.Lock() def Instance(self): """ Returns the singleton instance. Upon its first call, it creates a new instance of the decorated class and calls its `__init__` method. On all subsequent calls, the already created instance is returned. """ try: return self._instance except AttributeError: self.lock.acquire() try: return self._instance except AttributeError: self._instance = self._decorated() return self._instance finally: self.lock.release() def __call__(self): raise TypeError('Singletons must be accessed through `Instance()`.') def __instancecheck__(self, inst): return isinstance(inst, self._decorated)
You only need to add a decorator to the singleton class, as shown below:
@Singletonclass MySingletonClass: passs1 = MySingletonClass.Instance()s2 = MySingletonClass.Instance()
S1 and S2 are the same instances.
Attach a simple testcase:
import unittestfrom singleton import Singleton@Singletonclass A: passclass TestSingleton(unittest.TestCase): def testSingleton(self): a = A.Instance() aa = A.Instance() self.assertTrue(a is aa) def testSingletonCall(self): self.assertRaises(TypeError, A) def testIsinstance(self): a = A.Instance() self.assertTrue(isinstance(a, A)) self.assertFalse(isinstance(a, list))if __name__ == "__main__": unittest.main()