如何在Python中创建单例


如何在Python中创建单例


方法1:装饰者

def singleton(class_):
    instances = {}
    def getinstance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return getinstance

@singleton
class MyClass(BaseClass):
    pass

优点

装饰器的添加方式通常比多重继承更直观。

缺点

虽然使用MyClass()创建的对象将是真正的单例对象,但MyClass本身是一个函数,而不是一个类,因此您无法从中调用类方法。也适合m = MyClass(); n = MyClass(); o = type(n)();那时m == n && m != o && n != o

方法2:基类

class Singleton(object):
    _instance = None
    def __new__(class_, *args, **kwargs):
        if not isinstance(class_._instance, class_):
            class_._instance = object.__new__(class_, *args, **kwargs)
        return class_._instance

class MyClass(Singleton, BaseClass):
    pass

优点

这是一个真正的课程

缺点

多重继承 - eugh!__new__在从第二个基类继承期间可能被覆盖?人们必须思考的不仅仅是必要的。

方法3:元类

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

#Python2
class MyClass(BaseClass):
    __metaclass__ = Singleton

#Python3
class MyClass(BaseClass, metaclass=Singleton):
    pass

优点

这是一个真正的课程 自动神奇地涵盖了继承 使用__metaclass__它的正确用途(使我意识到这一点)

缺点

没有

方法4:装饰器返回一个具有相同名称的类

def singleton(class_):
    class class_w(class_):
        _instance = None
        def __new__(class_, *args, **kwargs):
            if class_w._instance is None:
                class_w._instance = super(class_w,
                                    class_).__new__(class_,
                                                    *args,
                                                    **kwargs)
                class_w._instance._sealed = False
            return class_w._instance
        def __init__(self, *args, **kwargs):
            if self._sealed:
                return
            super(class_w, self).__init__(*args, **kwargs)
            self._sealed = True
    class_w.__name__ = class_.__name__
    return class_w

@singleton
class MyClass(BaseClass):
    pass

优点

这是一个真正的课程 自动神奇地涵盖了继承

缺点

是否没有创建每个新类的开销?在这里,我们为每个我们希望制作单例的类创建两个类。虽然这在我的情况下很好,但我担心这可能无法扩展。当然,关于是否要过于容易地扩展这种模式存在争议...... 该_sealed属性的重点是什么 无法在基类上调用相同名称的方法,super()因为它们会递归。这意味着您无法自定义__new__并且无法子类化需要您调用的类__init__