摘要:前言單例模式是設計模式中最簡單最容易理解的一種,維基百科的定義如下單例模式,也叫單子模式,是一種常用的軟件設計模式。
前言
單例模式是設計模式(Design Pattern)中最簡單、最容易理解的一種,維基百科[1]的定義如下:
單例模式,也叫單子模式,是一種常用的軟件設計模式。在應用這個模式時,單例對象的類 "類 (計算機科學)")必須保證只有一個實例存在。許多時候整個系統只需要擁有一個的全局對象,這樣有利于我們協調系統整體的行為。
單例模式的主要優點是共享資源和減少資源消耗,主要應用于IO或數據庫的線程池,緩存,日志,對話和需共享數據的資源等,但是在實現情況中濫用單例模式會帶來很多意想不到的問題,本文重點在于介紹幾種Python實現單例模式的方法,這里就不再展開論述了。文中所演示的代碼都會托管在Github上。
簡單實現首先,我們先嘗試用Python內部類(嵌套類)來實現單例模式:
#coding=utf-8 class Singleton: """單列類 """ class __MyClass: """實際生成實例的類 """ def __init__(self, arg): """初始化并賦值""" self.foo = arg def display(self): """返回實例的id和屬性值""" return (id(self), self.foo) # 類屬性 _instance = None def __init__(self, arg): if not Singleton._instance: Singleton._instance = Singleton.__MyClass(arg) else: Singleton._instance.foo = arg def __getattr__(self, attr): return getattr(self._instance, attr)
注意實際生成實例的類是內部的“__MyClass”類,前面的雙下劃線代表這是一個私有的類,用戶不能再外面直接訪問它。而在"__MyClass"類外封裝了一個“Singleton”類,這個類的任務就是在初始化時保證整個上下文中只有一個實例,實現的方式很簡單。用一個私有屬性__instance_保存當前生成的實例,在初始化時判斷實例是否為_None_,如果是就用“__MyClass”類生成一個新實例并賦值給__instance_,否就直接返回或調用當前__instance_的實例。最后用"__MyClass"里的實現的方法測試一下:
if __name__ == "__main__": """測試""" s1 = Singleton("bar") s2 = Singleton("zoo") print(s1.display()) print(s2.display()) # output >(41706760L, "zoo") >(41706760L, "zoo")基類
現在我們考慮將inner class拆分出來,因為在Python類實例化時會調用___new___方法[2]來生成實例,所以我們可以先繼承“Singleton”類,然后通過重寫基類的___new___方法讓其實現單例模式:
#coding=utf-8 class Singleton(object): """單例類 """ _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance class MyClass(Singleton): """實際生成實例的類 """ def __init__(self, arg): self.foo = arg def display(self): return (id(self), self.foo)
測試結果:
if __name__ == "__main__": s1 = MyClass("bar") s2 = MyClass("zoo") print(s1.display()) print(s2.display()) assert s1 is s2 # output >(40882416L, "zoo") >(40882416L, "zoo")裝飾器
第三種就是最常見的用裝飾器來實現單列模式:
#coding=utf-8 def singleton(cls): instances = {} def wrapper(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class MyClass: """實際生成實例的類 """ foo = "foo" def display(self): return (id(self)) @singleton class OtherClass: """另一個類 """ pass
裝飾器的實現過程是將生成的實例都放到一個名為_instances_的Dict中映射好,這樣每次在類初始化時先檢查_instances_中是否已經包含有例化好的實例,有就直接返回是咧,沒有則調用類初始化一個并賦值給_instances_列表。裝飾器的好處在于用一個Dict列表來管理所有需要實現單例模式的類,更簡便和通用化。代碼的測試結果如下:
if __name__ == "__main__": s1 = MyClass() s1.foo = "bar" print(s1.display(), s1.foo) s2 = MyClass() s2.foo = "zoo" print(s2.display(), s2.foo) assert s1 is s2 s3 = OtherClass() s4 = OtherClass() assert s3 is s4元類
如果希望不僅僅是通過限制而是在源頭上就創建一個單例類,我們需要用到元類來實現,元類可以參考Stackoverflow[3]上的一個解答。簡單的說就是Python中的類也是一種對象,被稱為類對象。類對象可以通過元類type來創建,而在此過程中會調用type的 __call__ 方法。所以我們只要在type創建類對象的過程中重寫 __call__ 方法,在其中加入相應的創建單例的邏輯即可實現單例模式,具體代碼實現如下:
#coding=utf-8 class Singleton(type): def __call__(cls, *args, **kwargs): """重寫,實現單例模式""" if not hasattr(cls, "_instance"): cls._instance = super(Singleton, cls).__call__(*args, **kwargs) return cls._instance class MyClass(object): # 指定元類 __metaclass__ = Singleton def display(self): return (id(self))
代碼的測試與前面類似,這里就不再累述了。
線程安全最后,需要注意的是單例模式在多線程下可能會出現線程安全的問題,這時候就需要在單例的初始化過程中加上線程同步鎖來避免,但這樣又會降低整體的性能,具體可以參考這篇文檔。
參考[1]維基百科
[2]Python官方文檔
[3]Stackoverflow
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41304.html
摘要:本篇文章總結了目前主流的實現單例模式的方法供讀者參考。使用實現單例模式同樣,我們在類的創建時進行干預,從而達到實現單例的目的。 很多初學者喜歡用 全局變量 ,因為這比函數的參數傳來傳去更容易讓人理解。確實在很多場景下用全局變量很方便。不過如果代碼規模增大,并且有多個文件的時候,全局變量就會變得比較混亂。你可能不知道在哪個文件中定義了相同類型甚至重名的全局變量,也不知道這個變量在程序的某...
摘要:中的類都是單例模式一天,一同事問我這樣一個問題。與方法屬于新式類,即屬于類。方法在實例被創建之后被調用,該方法僅僅是對方法創建的實例進行一些初始化操作。需要注意的是,在重寫方法與方法的參數應該保持一致,否則會有發生。 Python 中的類都是單例模式? 一天,一同事問我這樣一個問題。這是一個奇怪的問題,可能你也這么認為。這里先不做解釋,我們先來看看 __new__ 和 __init__...
摘要:在中,我們可以用多種方法來實現單例模式使用模塊使用使用裝飾器使用元類使用模塊其實,的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成文件,當第二次導入時,就會直接加載文件,而不會再次執行模塊代碼。 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對...
摘要:實現實現單例模式有多種方案使用提供了非常易用的類,只要繼承它,就會成為單例。參考鏈接單例模式最后,感謝女朋友支持。 問題:現代化的巧克力工廠具備計算機控制的巧克力鍋爐。鍋爐做的事情就是把巧克力和牛奶融在一起,然后送到下一個階段,以制成巧克力棒。下邊是一個巧克力公司鍋爐控制器的代碼,仔細觀察一下,這段代碼有什么問題? class ChocolateBoiler(object): ...
摘要:使用元類可以控制類的創建過程,它主要做三件事攔截類的創建修改類的定義返回修改后的類使用元類實現單例模式的代碼如下執行結果 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 ...
閱讀 1037·2023-04-25 17:51
閱讀 2852·2021-11-23 09:51
閱讀 1470·2021-11-08 13:21
閱讀 2428·2021-09-22 15:14
閱讀 1515·2019-08-30 12:48
閱讀 1076·2019-08-29 12:44
閱讀 1138·2019-08-26 12:21
閱讀 1396·2019-08-26 10:47