python 单例模式总结

151 阅读2分钟

装饰器

def singleton(cls):
    def get_instance(*args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = cls(*args, **kwargs)
        return cls._instance
    return get_instance

元类

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance

继承

关于继承实现单例模式,我看了好多博客,都是通过cls._instance = super().__new__(cls, *args, **kwargs)来创建一个对象,但是呢, 这是错误的!!!

因为Singleton的超类是object,而object调用__new__方法的时候是不需要任何参数的。

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            # 注意,这个地方通过超类来获取实例的时候,传递的参数是超类需要的
            # 超类不需要的是不能传递的
            # 而这个地方Singleton的超类是object,因此是不需要任何参数,除了cls的
            cls._instance = super().__new__(cls)
        return cls._instance

点评

这三个方法实现单例模式,本质上是一致的。都是在创建新的实例的时候,会对该类是否已经创建了实例做判断。如果没有实例,则产生新的实例;如果已经有,则略过,返回旧的实例。

但是呢,通过继承实现的单例模式是有点突出的。因为它跟其他方式有点不同,它是通过new方法的改造实现的。如果之前有就返回之前的实例;如果没有,就创建新的实例。

需要知道的是,创建实例,有两个过程,一个是new方法创建实例对象,然后再由init方法初始化实例对象。

也就是继承那种方式,new返回的实例,会再通过init方法初始化。

也就是,其属性会得到更新。

class Singleton:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls)
        return cls._instance
 
class A(Singleton):
    def __init__(self, a, b):
        self.a = a
        self.b = b
 
    def __str__(self):
        return "a is " + str(self.a) + "; b is " + str(self.b)
a1 = A(1, 2)
print(a1)
a2 = A(2, 3)
print(a2)
print("a1 is a2 => ", a1 is a2)

结果是这样的

a is 1; b is 2
a is 2; b is 3
a1 is a2 =>  True

可以看见,实例的属性是得到更新的。。。。。

而其他两种方式中,都是在new方法之前对该类是否已有实例进行判断。