Thread-safe singleton in Python

Boris HUISGEN

The singleton is probably the most used design pattern to limit usage of resources like the number of connections to databases or any other services. Its implementation is relatively easy but it could be difficult to keep thread-safety.
Thread safety is generally solved by a synchronization system like a lock which Python owns with its primitive Lock from the threading package but some tricks are required to complete thread safety.
Implementation
1import logging
2import threading
3
4class MySingleton(object):
5 _instance: object = None
6 _lock: threading.Lock = threading.Lock()
7
8 def __new__(cls):
9 """Create a new instance"""
10 if MySingleton._instance is None:
11 with MySingleton._lock:
12 if MySingleton._instance is None:
13 MySingleton._instance = super(MySingleton, cls).__new__(cls)
14 MySingleton._instance._initialized = False
15
16 return MySingleton._instance
17
18 def __init__(self):
19 """Initialize the instance"""
20 if self._initialized is False:
21 self._logger = logging.getLogger(self.__class__.__name__)
22 self._count = 0
23 self._initialized = True
24
25 self._logger.debug("using instance: %s" % self._instance)
26
27 def increment(self):
28 """Increment the counter"""
29 self._count += 1
30
31 self._logger.debug("count = %d" % self._count)
The trick is to use a lock combined to another object which is going to keep the shared instance of your singleton class.
Test
To test that it works as needed let’s try it in a Python console:
>>> from code import MySingleton
>>> logging.basicConfig(level=logging.DEBUG, handlers=[logging.StreamHandler()])
>>> a = MySingleton()
DEBUG:MySingleton:using instance: <__main__.MySingleton object at 0x7f8bee80c550>
>>> b = MySingleton()
DEBUG:MySingleton:using instance: <__main__.MySingleton object at 0x7f8bee80c550>
>>> a.increment()
DEBUG:MySingleton:count = 1
>>> a.increment()
DEBUG:MySingleton:count = 2
>>> b.increment()
DEBUG:MySingleton:count = 3
As you can see the instances a and b are the same.