- 装饰器
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方法之前对该类是否已有实例进行判断。