The helpers/metaclasses subpackage provides Python metaclass implementations for structural patterns such as the
singleton, giving classes framework-level behavioral guarantees.
A thread-safe Singleton metaclass that ensures only one instance of a class is created.
This metaclass can be used to create Singleton classes. It supports an optional thread_safe
parameter to control whether thread-safety mechanisms (e.g., locks) should be used.
Attributes:
Name
Type
Description
_instances
dict
A dictionary to store instances of Singleton classes.
_lock
Lock
A lock to ensure thread-safe instance creation.
Example
To create a Singleton class, use the Singleton metaclass and optionally specify
whether thread-safety should be enabled:
classMySingletonClass(metaclass=Singleton,thread_safe=True):def__init__(self,value):self.value=value# Create instances of MySingletonClassinstance1=MySingletonClass(10)instance2=MySingletonClass(20)# Verify that both instances are the sameprint(instance1.value)# Output: 10print(instance2.value)# Output: 10print(instance1isinstance2)# Output: True
Source code in archipy/helpers/metaclasses/singleton.py
classSingleton(type):"""A thread-safe Singleton metaclass that ensures only one instance of a class is created. This metaclass can be used to create Singleton classes. It supports an optional `thread_safe` parameter to control whether thread-safety mechanisms (e.g., locks) should be used. Attributes: _instances (dict): A dictionary to store instances of Singleton classes. _lock (threading.Lock): A lock to ensure thread-safe instance creation. Example: To create a Singleton class, use the `Singleton` metaclass and optionally specify whether thread-safety should be enabled: ```python class MySingletonClass(metaclass=Singleton, thread_safe=True): def __init__(self, value): self.value = value # Create instances of MySingletonClass instance1 = MySingletonClass(10) instance2 = MySingletonClass(20) # Verify that both instances are the same print(instance1.value) # Output: 10 print(instance2.value) # Output: 10 print(instance1 is instance2) # Output: True ``` """_instances:ClassVar[dict[type,SingletonInstance]]={}# Stores instances of Singleton classes_lock:ClassVar[threading.Lock]=threading.Lock()# Lock for thread-safe instance creationdef__new__(cls,name:str,bases:ClassBases,dct:ClassDict,**kwargs:object,)->type:"""Create a new Singleton metaclass instance. Args: name (str): The name of the class. bases (tuple): The base classes of the class. dct (dict): The namespace containing the class attributes. **kwargs: Additional keyword arguments, including `thread_safe`. Returns: type: A new metaclass instance. """# Extract the `thread_safe` parameter from kwargsthread_safe=kwargs.pop("thread_safe",True)# Create the new classnew_class=super().__new__(cls,name,bases,dct,**kwargs)# Store thread_safe as an attribute using setattr to avoid linting errorssetattr(new_class,"__thread_safe",thread_safe)returnnew_classdef__call__(cls,*args:object,**kwargs:object)->SingletonInstance:"""Create or return the Singleton instance of the class. If `thread_safe` is True, a lock is used to ensure that only one instance is created even in a multi-threaded environment. If `thread_safe` is False, no locking mechanism is used, which may result in multiple instances being created in a multi-threaded context. Args: *args: Positional arguments to pass to the class constructor. **kwargs: Keyword arguments to pass to the class constructor. Returns: object: The Singleton instance of the class. """ifclsnotincls._instances:ifgetattr(cls,"__thread_safe",True):withcls._lock:ifclsnotincls._instances:cls._instances[cls]=super().__call__(*args,**kwargs)else:cls._instances[cls]=super().__call__(*args,**kwargs)returncls._instances[cls]