Python實(shí)現(xiàn)設(shè)計(jì)模式之單例模式詳解
設(shè)計(jì)模式簡(jiǎn)介
設(shè)計(jì)模式是指軟件設(shè)計(jì)問(wèn)題的推薦方案。設(shè)計(jì)模式一般是描述如何組織代碼和使用最佳實(shí)踐來(lái)解決常見的設(shè)計(jì)問(wèn)題。需謹(jǐn)記一點(diǎn):設(shè)計(jì)模式是高層次的方案,并不關(guān)注具體的實(shí)現(xiàn)細(xì)節(jié),比如算法和數(shù)據(jù)結(jié)構(gòu)。
設(shè)計(jì)模式共分為三大類,細(xì)分為23種設(shè)計(jì)模式。
1. 創(chuàng)建型模式
2. 結(jié)構(gòu)型模式
3. 行為型模式
單例
單例模式屬于創(chuàng)建型模式,是一個(gè)比較常用的一個(gè)設(shè)計(jì)模式,單例模式主要作用是讓一個(gè)類只有一個(gè)實(shí)例對(duì)象,因?yàn)樵谀承r(shí)候創(chuàng)建多個(gè)實(shí)例對(duì)象會(huì)浪費(fèi)內(nèi)存,所以目的就是為了節(jié)省內(nèi)存資源。
既然是約束只能生成一個(gè)實(shí)例對(duì)象,那么就應(yīng)該在實(shí)例化的過(guò)程進(jìn)行修改,編寫單例的方法有很多種
使用元類 __call__
代碼示例(基于元類)
class Single(type): # 定義繼承元類type的類 def __call__(self, *args, **kwargs): # 重寫 __call__ 在類加括號(hào)調(diào)用時(shí)執(zhí)行 if not hasattr(self, 'new_obj'): # 判斷類名有沒有指定屬性 # 若沒有,則添加指定屬性,屬性值是元類__call__的返回值也就是類名 self.new_obj = super().__call__(*args, **kwargs) return self.new_obj class MyClass(metaclass=Single): def __init__(self, name): self.name = name obj1 = MyClass('X') obj2 = MyClass('W') print(obj1 is obj2) print(obj1) print(obj2)
打印結(jié)果
True
<__main__.MyClass object at 0x000001F9B382E350>
<__main__.MyClass object at 0x000001F9B382E350>
此時(shí)創(chuàng)建多個(gè)實(shí)例并不會(huì)執(zhí)行,只指向一個(gè)實(shí)例。
使用 __new__ 方法
__new__ 方法在類的實(shí)例化過(guò)程最先執(zhí)行,默認(rèn)執(zhí)行 object 的 __new__ 方法,返回一個(gè)實(shí)例化對(duì)象,然后再調(diào)用 __init__ 方法,對(duì)這個(gè)對(duì)象進(jìn)行初始化
class MyCls(object): # 定義繼承元類type的類 def __new__(cls, *args, **kwargs): # 重寫 __new__ 方法 if not hasattr(cls, 'new_obj'): # 如果類名沒有指定屬性 # 給類名添加屬性,屬性值是 object 的__new__方法返回值 cls.new_obj = super().__new__(cls, *args, **kwargs) return cls.new_obj # 將屬性值返回 obj = MyCls() obj1 = MyCls() print(obj is obj1) print(obj) print(obj1)
打印結(jié)果
True
<__main__.MyCls object at 0x0000024968276500>
<__main__.MyCls object at 0x0000024968276500>
第一次實(shí)例化的時(shí)候,由于判斷其沒有指定屬性,執(zhí)行添加屬性語(yǔ)句,屬性值是 object 的 __new__ 方法的返回值,最后返回指定屬性的值,也就是類名,而第二次實(shí)例化的時(shí)候由于已經(jīng)添加了屬性,所以直接返回object 的 __new__ 方法,所以其實(shí)他們一直是同一個(gè)屬性值。
使用 @classmethod
@classmethod 會(huì)自動(dòng)將類名傳入到 cls 變量中
class MyCls(object): _instance = None # 定義一個(gè)變量用于判斷 def __init__(self): pass @classmethod # 定義一個(gè)類方法 def singleton(cls): if not cls._instance: # 如果類中的指定屬性為None cls._instance = MyCls() # 設(shè)置屬性,屬性值為實(shí)例對(duì)象 return cls._instance # 將指定屬性返回 obj1 = MyCls.singleton() # 只能用類方法來(lái)獲取實(shí)例對(duì)象 obj2 = MyCls.singleton() # 只能用類方法來(lái)獲取實(shí)例對(duì)象 print(obj1) print(obj2)
打印結(jié)果
<__main__.MyCls object at 0x000002396ABB5D20>
<__main__.MyCls object at 0x000002396ABB5D20>
這個(gè)有些不同,只能用類方法來(lái)獲取實(shí)例對(duì)象。第一次調(diào)用類方法創(chuàng)建實(shí)例對(duì)象的時(shí)候在類方法中得到了一個(gè)實(shí)例對(duì)象返回值,而在第二次調(diào)用類方法創(chuàng)建對(duì)象的時(shí)候已經(jīng)有了指定屬性,不滿足類方法中的判斷條,所以獲得的還是第一次實(shí)例化得到的對(duì)象。
使用裝飾器
使用裝飾器實(shí)現(xiàn)實(shí)例化并返回出來(lái)
def outer(cls): # 定義裝飾器 _instance = None # 定義變量用于判斷 def inner(*args, **kwargs): nonlocal _instance # 聲明變量 if not _instance: # 如果變量是 None _instance = cls(*args, **kwargs) # 設(shè)置屬性,屬性值為實(shí)例對(duì)象 return _instance return inner @outer # 調(diào)用裝飾器,將類名傳入到cls,也就是此時(shí)相當(dāng)于 outer(MyCls) class MyCls: pass obj = MyCls() obj1 = MyCls() print(obj) print(obj1)
打印結(jié)果
<__main__.MyCls object at 0x00000165FDE05D20>
<__main__.MyCls object at 0x00000165FDE05D20>
使用模塊
模塊的方式就是在一個(gè)py文件中定義一個(gè)類,并實(shí)例化一個(gè)對(duì)象,之后在其他文件導(dǎo)入這一對(duì)象
到此這篇關(guān)于Python實(shí)現(xiàn)設(shè)計(jì)模式之單例模式詳解的文章就介紹到這了,更多相關(guān)Python單例模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python人工智能實(shí)戰(zhàn)之以圖搜圖的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了如何基于vgg網(wǎng)絡(luò)和Keras深度學(xué)習(xí)框架實(shí)現(xiàn)以圖搜圖功能。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2022-05-05詳解java調(diào)用python的幾種用法(看這篇就夠了)
這篇文章主要介紹了詳解java調(diào)用python的幾種用法(看這篇就夠了),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12PyTorch實(shí)現(xiàn)重寫/改寫Dataset并載入Dataloader
這篇文章主要介紹了PyTorch實(shí)現(xiàn)重寫/改寫Dataset并載入Dataloader,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07python運(yùn)行cmd命令行的3種方法總結(jié)
雖然python在調(diào)用cmd命令方面使用的比較少,不過(guò)還是要用的,下面這篇文章主要給大家介紹了關(guān)于python運(yùn)行cmd命令行的3種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Django用戶認(rèn)證系統(tǒng) User對(duì)象解析
這篇文章主要介紹了Django用戶認(rèn)證系統(tǒng) User對(duì)象解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Python 獲取div標(biāo)簽中的文字實(shí)例
今天小編就為大家分享一篇Python 獲取div標(biāo)簽中的文字實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12