hbutils.design.singleton

Singleton pattern utilities for Python applications.

This module provides metaclasses and helper utilities for implementing various forms of the singleton design pattern. The provided components allow you to create traditional singleton classes (one instance for the entire lifetime) as well as value-based singletons (one instance per unique value), along with a convenient marker class for sentinel values.

The module contains the following main components:

Note

The metaclasses in this module intentionally control instantiation, and their __call__ signatures are constrained to match their intended usage.

Example:

>>> class Service(metaclass=SingletonMeta):
...     def get_value(self) -> int:
...         return 233
...
>>> s1 = Service()
>>> s2 = Service()
>>> s1 is s2
True
>>> s1.get_value()
233

>>> class Data(metaclass=ValueBasedSingletonMeta):
...     def __init__(self, value: int) -> None:
...         self.value = value
...
>>> d1 = Data(1)
>>> d2 = Data(1)
>>> d3 = Data(2)
>>> d1 is d2
True
>>> d1 is d3
False

>>> NO_VALUE = SingletonMark("no_value")
>>> NO_VALUE is SingletonMark("no_value")
True

__all__

hbutils.design.singleton.__all__ = ['SingletonMeta', 'ValueBasedSingletonMeta', 'SingletonMark']

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

SingletonMeta

class hbutils.design.singleton.SingletonMeta[source]

Meta class for singleton mode.

This metaclass ensures that only one instance of a class is created throughout the application’s lifetime. Subsequent calls to the class constructor will return the same instance.

Example::
>>> class MyService(metaclass=SingletonMeta):
...     def get_value(self):
...         return 233
>>>
>>> s = MyService()
>>> s.get_value()    # 233
>>> s1 = MyService()
>>> s1 is s          # True

Note

In native singleton pattern, the constructor is not needed because only one instance will be created in the whole lifetime. So when SingletonMeta is used as metaclass, please keep the constructor be non-argument, or just ignore the __init__ function.

__call__() Any[source]

Override the call method to control instance creation.

This implementation accepts no arguments and returns the same instance every time it is called for the same class.

Returns:

The singleton instance of the class.

Return type:

object

ValueBasedSingletonMeta

class hbutils.design.singleton.ValueBasedSingletonMeta[source]

Meta class for value based singleton mode.

This metaclass creates singleton instances based on a value parameter. Multiple calls with the same value will return the same instance, while different values will create different instances.

Example::
>>> class MyData(metaclass=ValueBasedSingletonMeta):
...     def __init__(self, value):
...         self.__value = value
>>>
...     @property
...     def value(self):
...         return self.__value
>>>
>>> d1 = MyData(1)
>>> d1.value       # 1
>>> d2 = MyData(1)
>>> d3 = MyData(2)
>>> d2 is d1       # True
>>> d2 is d3       # False

Note

This is an external case of singleton pattern. It can only contain one argument (must be positional-supported), which differs from the native singleton case.

__call__(value: Hashable) Any[source]

Override the call method to control instance creation based on value.

Parameters:

value (Hashable) – The value used as key for singleton instance lookup.

Returns:

The singleton instance associated with the given value.

Return type:

object

SingletonMark

class hbutils.design.singleton.SingletonMark(value: Hashable)[source]

Singleton mark for some situation.

Can be used when some default value is needed, especially when None has meaning which is not default. This class creates unique marker objects that can be used as sentinel values.

Example::
>>> NO_VALUE = SingletonMark("no_value")
>>> NO_VALUE is SingletonMark("no_value")  # True

Note

SingletonMark is a value-based singleton class, can be used to create an unique value, especially in the cases which None is not suitable for the default value.

__eq__(other: Any) bool[source]

Compare equality between singleton marks.

SingletonMark objects can be directly compared with ==.

Parameters:

other (Any) – The object to compare with.

Returns:

True if marks are equal, False otherwise.

Return type:

bool

Examples::
>>> mark1 = SingletonMark('mark1')
>>> mark1x = SingletonMark('mark1')
>>> mark2 = SingletonMark('mark2')
>>> mark1 == mark1
True
>>> mark1 == mark1x
True
>>> mark1 == mark2
False
__hash__() int[source]

Compute hash value for the singleton mark.

SingletonMark objects are hash supported and can be directly used in dict and set.

Returns:

Hash value of the mark.

Return type:

int

__init__(mark: str) None[source]

Constructor of SingletonMark, can create a singleton mark object.

Parameters:

mark (str) – The string identifier for this mark.

__repr__() str[source]

Return string representation of the singleton mark.

When you try to print a SingletonMark object, its mark content will be displayed.

Returns:

String representation of the mark.

Return type:

str

Examples::
>>> mark1 = SingletonMark('mark1')
>>> print(mark1)
<SingletonMark 'mark1'>
property mark: str

Get mark string of this mark object.

Returns:

Mark string identifier.

Return type:

str