摘要:本篇文章總結了目前主流的實現單例模式的方法供讀者參考。使用實現單例模式同樣,我們在類的創建時進行干預,從而達到實現單例的目的。
很多初學者喜歡用 全局變量 ,因為這比函數的參數傳來傳去更容易讓人理解。確實在很多場景下用全局變量很方便。不過如果代碼規模增大,并且有多個文件的時候,全局變量就會變得比較混亂。你可能不知道在哪個文件中定義了相同類型甚至重名的全局變量,也不知道這個變量在程序的某個地方被做了怎樣的操作。
因此對于這種情況,有種更好的實現方式:
單例(Singleton)
單例是一種 設計模式 ,應用該模式的類只會生成一個實例。
單例模式保證了在程序的不同位置都 可以且僅可以取到同一個對象實例 :如果實例不存在,會創建一個實例;如果已存在就會返回這個實例。因為單例是一個類,所以你也可以為其提供相應的操作方法,以便于對這個實例進行管理。
舉個例子來說,比如你開發一款游戲軟件,游戲中需要有“場景管理器”這樣一種東西,用來管理游戲場景的切換、資源載入、網絡連接等等任務。這個管理器需要有多種方法和屬性,在代碼中很多地方會被調用,且被調用的必須是同一個管理器,否則既容易產生沖突,也會浪費資源。這種情況下,單例模式就是一個很好的實現方法。
單例模式廣泛應用于各種開發場景,對于開發者而言是必須掌握的知識點,同時在很多面試中,也是常見問題。本篇文章總結了目前主流的實現單例模式的方法供讀者參考。
希望看過此文的同學,在以后被面到此問題時,能直接皮一下面試官,“我會 4 種單例模式實現,你想聽哪一種?”
以下是實現方法索引:
使用函數裝飾器實現單例
使用類裝飾器實現單例
使用 new 關鍵字實現單例
使用 metaclass 實現單例
使用函數裝飾器實現單例以下是實現代碼:
def singleton(cls): _instance = {} def inner(): if cls not in _instance: _instance[cls] = cls() return _instance[cls] return inner @singleton class Cls(object): def __init__(self): pass cls1 = Cls() cls2 = Cls() print(id(cls1) == id(cls2))
輸出結果:
True
在 Python 中,id 關鍵字可用來查看對象在內存中的存放位置,這里 cls1 和 cls2 的 id 值相同,說明他們指向了同一個對象。
關于裝飾器的知識,有不明白的同學可以查看之前的文章 【編程課堂】裝飾器淺析 或者使用搜索引擎再學習一遍。代碼中比較巧妙的一點是:
_instance = {}
使用不可變的 類地址 作為鍵,其實例作為值,每次創造實例時,首先查看該類是否存在實例,存在的話直接返回該實例即可,否則新建一個實例并存放在字典中。
使用類裝飾器實現單例代碼:
class Singleton(object): def __init__(self, cls): self._cls = cls self._instance = {} def __call__(self): if self._cls not in self._instance: self._instance[self._cls] = self._cls() return self._instance[self._cls] @Singleton class Cls2(object): def __init__(self): pass cls1 = Cls2() cls2 = Cls2() print(id(cls1) == id(cls2))
同時,由于是面對對象的,這里還可以這么用
class Cls3(): pass Cls3 = Singleton(Cls3) cls3 = Cls3() cls4 = Cls3() print(id(cls3) == id(cls4))
使用 類裝飾器實現單例的原理和 函數裝飾器 實現的原理相似,理解了上文,再理解這里應該不難。
New、Metaclass 關鍵字在接著說另外兩種方法之前,需要了解在 Python 中一個類和一個實例是通過哪些方法以怎樣的順序被創造的。
簡單來說, 元類 ( metaclass ) 可以通過方法 metaclass 創造了 類(class) ,而 類(class) 通過方法 new 創造了 實例(instance) 。
在單例模式應用中,在創造類的過程中或者創造實例的過程中稍加控制達到最后產生的實例都是一個對象的目的。
本文主講單例模式,所以對這個 topic 只會點到為止,有感興趣的同學可以在網上搜索相關內容,幾篇參考文章:
What are metaclasses in Python?
https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
python-__new__-magic-method-explained
http://howto.lintel.in/python-__new__-magic-method-explained/
Why is __init__() always called after __new__()?
https://stackoverflow.com/questions/674304/why-is-init-always-called-after-new
使用 new 關鍵字實現單例模式使用 new 方法在創造實例時進行干預,達到實現單例模式的目的。
class Single(object): _instance = None def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = object.__new__(cls, *args, **kw) return cls._instance def __init__(self): pass single1 = Single() single2 = Single() print(id(single1) == id(single2))
在理解到 new 的應用后,理解單例就不難了,這里使用了
_instance = None
來存放實例,如果 _instance 為 None,則新建實例,否則直接返回 _instance 存放的實例。
使用 metaclass 實現單例模式同樣,我們在類的創建時進行干預,從而達到實現單例的目的。
在實現單例之前,需要了解使用 type 創造類的方法,代碼如下:
def func(self): print("do sth") Klass = type("Klass", (), {"func": func}) c = Klass() c.func()
以上,我們使用 type 創造了一個類出來。這里的知識是 mataclass 實現單例的基礎。
class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class Cls4(metaclass=Singleton): pass cls1 = Cls4() cls2 = Cls4() print(id(cls1) == id(cls2))
這里,我們將 metaclass 指向 Singleton 類,讓 Singleton 中的 type 來創造新的 Cls4 實例。
小結本文雖然是講單例模式,但在實現單例模式的過程中,涉及到了蠻多高級 Python 語法,包括裝飾器、元類、new、type 甚至 super 等等。對于新手同學可能難以理解,其實在工程項目中并不需要你掌握的面面俱到,掌握其中一種,剩下的作為了解即可。
by 周鑫鑫
關于更多的設計模式,給初學者推薦《 Head First 設計模式 》(Head First Design Patterns),此書淺顯易懂,在 Head First 系列書籍里面也算是很好的一本。
我們的資源網盤里有電子版,獲取地址請在公眾號( Crossin的編程教室 )里回復關鍵字: 資源
════
其他文章及回答:
如何自學Python | 新手引導 | 精選Python問答 | Python單詞表 | 區塊鏈 | 人工智能 | 雙11 | 嘻哈 | 爬蟲 | 排序算法
歡迎搜索及關注: Crossin的編程教室
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42490.html
摘要:中的類都是單例模式一天,一同事問我這樣一個問題。與方法屬于新式類,即屬于類。方法在實例被創建之后被調用,該方法僅僅是對方法創建的實例進行一些初始化操作。需要注意的是,在重寫方法與方法的參數應該保持一致,否則會有發生。 Python 中的類都是單例模式? 一天,一同事問我這樣一個問題。這是一個奇怪的問題,可能你也這么認為。這里先不做解釋,我們先來看看 __new__ 和 __init__...
摘要:前言單例模式是設計模式中最簡單最容易理解的一種,維基百科的定義如下單例模式,也叫單子模式,是一種常用的軟件設計模式。 前言 單例模式是設計模式(Design Pattern)中最簡單、最容易理解的一種,維基百科[1]的定義如下: 單例模式,也叫單子模式,是一種常用的軟件設計模式。在應用這個模式時,單例對象的類 類 (計算機科學))必須保證只有一個實例存在。許多時候整個系統只需要擁有一...
摘要:在中,我們可以用多種方法來實現單例模式使用模塊使用使用裝飾器使用元類使用模塊其實,的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成文件,當第二次導入時,就會直接加載文件,而不會再次執行模塊代碼。 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對...
摘要:使用元類可以控制類的創建過程,它主要做三件事攔截類的創建修改類的定義返回修改后的類使用元類實現單例模式的代碼如下執行結果 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 ...
摘要:博主按每天一個設計模式旨在初步領會設計模式的精髓,目前采用靠這吃飯和純粹喜歡兩種語言實現。單例模式用途如果一個類負責連接數據庫的線程池日志記錄邏輯等等,此時需要單例模式來保證對象不被重復創建,以達到降低開銷的目的。 博主按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前采用javascript(_靠這吃飯_)和python(_純粹喜歡_)兩種語言實現。誠然,每種設計模式都有多種實...
閱讀 2504·2021-11-15 11:38
閱讀 1948·2021-11-05 09:37
閱讀 2256·2021-10-08 10:12
閱讀 2807·2019-08-30 15:55
閱讀 2112·2019-08-30 15:52
閱讀 1220·2019-08-29 13:24
閱讀 463·2019-08-26 18:27
閱讀 1472·2019-08-26 18:27