@asSingleton¶
Enforce the singleton pattern with a simple decorator.
xpytools.xdeco.asSingleton.asSingleton
¶
Enforces singleton behavior by wrapping the class in a custom subclass.
Prevents the user-defined class from defining its own __new__, which would
conflict with the singleton logic.
:param cls: The class to wrap :return: A singleton-enforcing subclass of the original
Source code in xpytools/xdeco/asSingleton.py
Python
def asSingleton(cls: type) -> type:
"""
Enforces singleton behavior by wrapping the class in a custom subclass.
Prevents the user-defined class from defining its own `__new__`, which would
conflict with the singleton logic.
:param cls: The class to wrap
:return: A singleton-enforcing subclass of the original
"""
if "__new__" in cls.__dict__:
raise _SingletonViolationException(cls)
for attr in cls.__dict__:
if attr.endswith("__cls_instance") or attr == "__cls_instance":
raise _SingletonViolationException(cls)
class SingletonWrapper(cls):
__cls_instance = None
def __new__(cls_, *args, **kwargs):
if cls_.__cls_instance is None:
cls_.__cls_instance = super(SingletonWrapper, cls_).__new__(cls_)
return cls_.__cls_instance
def __init__(self, *args, **kwargs):
if not getattr(self, '__singleton_initialized__', False):
super(SingletonWrapper, self).__init__(*args, **kwargs)
setattr(self, '__singleton_initialized__', True)
SingletonWrapper.__name__ = cls.__name__
SingletonWrapper.__qualname__ = cls.__qualname__
SingletonWrapper.__doc__ = cls.__doc__
return SingletonWrapper