Implementing the Singleton Pattern in Python: Multiple Approaches
This article explains the Singleton design pattern in Python and presents seven implementation techniques—including module‑level variables, module instances, decorators, metaclasses, class methods, and thread‑safe approaches—complete with code examples and guidance on choosing the appropriate method.
Singleton Pattern is a common software design pattern that ensures a class has only one instance throughout an application and provides a global access point.
1. Module-level variable – because a module is imported only once, a variable defined at module level naturally behaves as a singleton.
# singleton.py
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
# usage
from singleton import Singleton
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True2. Module-level instance – define an instance directly in a module and import that instance wherever needed.
# singleton_module.py
class SingletonClass:
pass
singleton_instance = SingletonClass()
# usage
from singleton_module import singleton_instance
print(id(singleton_instance)) # same id each import3. Decorator – a decorator can wrap a class to guarantee a single instance.
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class MyClass:
pass
s1 = MyClass()
s2 = MyClass()
print(s1 is s2) # True4. Metaclass – a metaclass controls class creation and can store a single instance per class.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonViaMeta(metaclass=SingletonMeta):
pass
s1 = SingletonViaMeta()
s2 = SingletonViaMeta()
print(s1 is s2) # True5. Class method – expose a class method that lazily creates and returns a single instance.
class SingletonClassMethod:
__instance = None
@classmethod
def get_instance(cls):
if not cls.__instance:
cls.__instance = SingletonClassMethod()
return cls.__instance
s1 = SingletonClassMethod.get_instance()
s2 = SingletonClassMethod.get_instance()
print(s1 is s2) # True6. __new__ with thread safety – protect instance creation with a lock to be safe in multithreaded environments.
import threading
class ThreadSafeSingleton:
__instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
with cls._lock:
if not cls.__instance:
cls.__instance = super().__new__(cls, *args, **kwargs)
return cls.__instance
s1 = ThreadSafeSingleton()
s2 = ThreadSafeSingleton()
print(s1 is s2) # True, thread‑safe7. __new__ combined with metaclass – merge metaclass control with a lock for a clean, thread‑safe singleton.
class ThreadSafeSingletonMeta(type):
_instances = {}
_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
with cls._lock:
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonMetaSafe(metaclass=ThreadSafeSingletonMeta):
pass
s1 = SingletonMetaSafe()
s2 = SingletonMetaSafe()
print(s1 is s2) # True, thread‑safeConclusion – Python offers many ways to implement a singleton; the choice depends on personal preference, project requirements, and whether thread safety is needed. The examples above range from simple module‑level instances to advanced metaclass solutions.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.