TOC

Python 单例模式

使用全局变量

我个人比较喜欢的方式,简单高效。

class Application:
    pass

APP = Application()

装饰器(使用特定方法来获取对象实例)

import threading

class singleton:
    _instance_lock = threading.Lock()

    def __init__(self, decorated):
        self._decorated = decorated

    def instance(self):
        if not hasattr(self, '_instance'):
            with singleton._instance_lock:
                if not hasattr(self, '_instance'):
                    self._instance = self._decorated()
        return self._instance

    def __call__(self):
        raise TypeError('Singletons must be accessed through `instance()`.')

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

    def __getattr__(self, name):
        if name == '_instance':
            raise AttributeError("'singleton' object has no attribute '_instance'")
        return getattr(self.instance(), name)

@singleton
class Application:
    pass

Application.instance()

装饰器

def singleton(cls):
    _instances = {}

    def _inner(*args, **kargs):
        if cls not in _instances:
            _instances[cls] = cls(*args, **kargs)
        return _instances[cls]

    return _inner

元类

class Application:
    _instance_lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = object.__new__(cls)
        return cls._instance

改成通用方式:

import threading

class SingletonMeta(type):
    _instances = {}
    _instance_lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            with cls._instance_lock:
                if cls not in cls._instances:
                    instance = super().__call__(*args, **kwargs)
                    cls._instances[cls] = instance
        return cls._instances[cls]

class Application(metaclass=SingletonMeta):
    pass