Source code for hbutils.design.singleton

"""
Overview:
    Implement of singleton design pattern.
"""
__all__ = [
    'SingletonMeta',
    'ValueBasedSingletonMeta',
    'SingletonMark',
]


[docs]class SingletonMeta(type): """ Overview: Meta class for singleton mode. 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 \ :class:`SingletonMeta` is used as metaclass, please keep the constructor \ be non-argument, or just ignore the ``__init__`` function. """ _instances = {}
[docs] def __call__(cls): if cls not in cls._instances: cls._instances[cls] = super(SingletonMeta, cls).__call__() return cls._instances[cls]
[docs]class ValueBasedSingletonMeta(type): """ Overview: Meta class for value based singleton mode. 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. """ _instances = {}
[docs] def __call__(cls, value): key = (cls, value) if key not in cls._instances: cls._instances[key] = super(ValueBasedSingletonMeta, cls).__call__(value) return cls._instances[key]
[docs]class SingletonMark(metaclass=ValueBasedSingletonMeta): """ Overview: Singleton mark for some situation. Can be used when some default value is needed, especially when `None` has meaning which is not default. Example: >>> NO_VALUE = SingletonMark("no_value") >>> NO_VALUE is SingletonMark("no_value") # True .. note:: :class:`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. """
[docs] def __init__(self, mark): """ Overview: Constructor of :class:`SingletonMark`, can create a singleton mark object. """ self.__mark = mark
@property def mark(self): """ Overview: Get mark string of this mark object. Returns: - mark (:obj:`str`): Mark string """ return self.__mark
[docs] def __hash__(self): """ Overview: :class:`SingletonMark` objects are hash supported. can be directly used \ in :class:`dict` and :class:`set`. """ return hash(self.__mark)
[docs] def __eq__(self, other): """ Overview: :class:`SingletonMark` objects can be directly compared with ``==``. Examples:: >>> mark1 = SingletonMark('mark1') >>> mark1x = SingletonMark('mark1') >>> mark2 = SingletonMark('mark2') >>> mark1 == mark1 True >>> mark1 == mark1x True >>> mark1 == mark2 False """ if other is self: return True elif type(other) == type(self): return other.__mark == self.__mark else: return False
[docs] def __repr__(self): """ Overview: When you try to print a :class:`SingletonMark` object, its mark content will be \ displayed. Examples:: >>> mark1 = SingletonMark('mark1') >>> print(mark1) <SingletonMark mark1> """ return "<{cls} {mark}>".format( cls=self.__class__.__name__, mark=repr(self.__mark), )