python 設計模式(一) 單例模式

單例模式

單例模式:不管用類實例化對象多少次,所得到的對象都是同一個對象。這種模式的應用場景,如數據庫連接,配置信息等。

1 通過類的嵌套實現單例

# create singleton by means of class nestification

class Singleton(object):
    # really working class
    class Wrapper_class(object):

        def __init__(self, name):
            self.name = name

        def show_id(self):
            return id(self)

        def work(self):
            print('i am working')

    # save Wrapper_class instance
    _instance = None

    def __init__(self):
        if Singleton._instance is None:
            Singleton._instance = Singleton.Wrapper_class('wrapper')
    # when get attribute if not exist, call this function. it return getattr function. 
    def __getattr__(self, item):
        return getattr(self._instance, item)
    # getattr include three params: instance name, attribute or method name, default value when instance not include attribute

if __name__ == '__main__':
    a = Singleton()
    b = Singleton()
    print(a)
    print(b)
    print(a.show_id())
    print(b.show_id())

以上代碼修改自實驗樓--python設計模式--單例。如有侵權請聯繫[email protected]

代碼解析:Wrapper_class類是真正幹活的類,它只進行一次實例化,並用Singleton類變量_instance保存,不管對Singleton類進行多少次實例化,內部由Wrapper_class類實例化出的幹活的對象就只有一個。

Singleton類的方法__getattr__作用是:當調用了Singleton類不存在的方法或者屬性時,就會運行Singleton的__getattr__方法。

return getattr(對象,屬性或方法) 作用:檢查屬性或方法是否屬於對象,屬於的話,調用這個方法或者對象。

本例中,調用了Singleton類實例化對象的show_id()方法,但Singleton類中並未實現這個方法,因此首先調用了Singleton類的__getattr__方法,並返回了getattr(self._instance, item)方法,這個方法首先檢查Wrapper_class類實例化的保存在_instance中的對象是否具有show_id()方法,正好Wrapper_class類中實現了這個方法,因此運行了這個方法,得到了結果

<__main__.Singleton object at 0x000002346197C358>
<__main__.Singleton object at 0x000002346197C550>
2423998891120
2423998891120
由結果知,不管實例化多少次Singleton類,但最終幹活的對象都是同一個

2 裝飾器實現單例

利用類裝飾器實現單例

先上代碼吧

# create singleton by means of class decorator
class Decorator(object):

    def __init__(self, cls):
        self._cls = cls

    def __call__(self, *args, **kwargs):
        try:
            return self._instance
        except AttributeError:
            self._instance = self._cls()
            return self._instance


@Decorator
class Work(object):

    def __init__(self):
        pass

    def show_id(self):
        return id(self)


if __name__ == '__main__':
    a = Work()
    b = Work()
    print(a.show_id())
    print(b.show_id())

結果爲

1969722475520
1969722475520

上述代碼中,類Decorator是裝飾器類,其override了__call___方法,進行了custom。__call__方法使類Decorator實例化的對象可以像函數一樣被調用。因此可以當做裝飾器裝飾其他函數或類。只有可調用對象才能作爲裝飾器

對於用函數去裝飾函數這樣的簡單的裝飾器類型,很容易理解其中代碼的執行流程。但理解類裝飾類這種類型確實讓我頭疼。就比葫蘆畫瓢地理解吧。函數裝飾函數類型:裝飾後返回的是裝飾器內層的函數,然後替代原來的函數。那麼同理,用類去裝飾類,裝飾後返回的應該是裝飾器中的類的實例(別打臉,我猜的)。先就這樣理解吧。正如上面的例子。類Work被類Decorator裝飾,那麼裝飾後類Work就被傳遞進了Decorator的self._cls位置。然後把類Decorator的實例返回,並代替類Work的位置。當調用類Work進行實例化時,實際上調用的是裝飾過以後的類Decorator的實例。仔細觀察類Decorator的代碼,可知,首次創建的時候,會生成一個實例屬性self._instance。當第二次進行調用的時候,直接返回的是self._instance。因此就實現了單例模式。我對這段代碼還是有很多疑惑。真正懂的大神可以評論告訴我啊,小弟在這裏先謝過,有人說,這段代碼不能用於多線程,我沒試過,大家注意下

3 通過__new__方法實現單例

# crate singleton by means of __new__
class Singleton(object):
    _instance = None # 一個下劃線開頭表示受保護的屬性

    # __new__函數在調用__init__方法前調用,目的是創建一個對象,因此,其方法的第一個參數要傳遞類名,cls,而不是self
    # 只有創建了對象後才能使用self
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
    
if __name__ == '__main__':

    a = Singleton()
    b = Singleton()
    print(id(a), id(b))

結果爲

2025743751544 2025743751544

總結:

    以上通過三種方法實現了單例模式,但實際項目中,也可以不使用單例模式,而只在初始化時,創建一個實例,其他模塊共用這個實例,這同樣能實現單例的效果。




發佈了54 篇原創文章 · 獲贊 11 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章