python實現單例模式總結

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章