- 裝飾器
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方法之前對該類是否已有實例進行判斷。