Python實(shí)現(xiàn)單例模式的最佳方法匯總
Python中實(shí)現(xiàn)單例模式的最佳方法
技術(shù)背景
單例模式是一種創(chuàng)建型設(shè)計(jì)模式,它確保一個(gè)類(lèi)只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)來(lái)獲取這個(gè)實(shí)例。在Python中,有多種方式可以實(shí)現(xiàn)單例模式,不同的實(shí)現(xiàn)方式各有優(yōu)缺點(diǎn),適用于不同的場(chǎng)景。
實(shí)現(xiàn)步驟
方法1:使用裝飾器
def singleton(class_): instances = {} def getinstance(*args, **kwargs): if class_ not in instances: instances[class_] = class_(*args, **kwargs) return instances[class_] return getinstance @singleton class MyClass(BaseClass): pass
- 優(yōu)點(diǎn):裝飾器的使用方式直觀,比多重繼承更具可讀性。
- 缺點(diǎn):使用
MyClass()
創(chuàng)建的對(duì)象是單例對(duì)象,但MyClass
本身是一個(gè)函數(shù),不是類(lèi),因此不能調(diào)用類(lèi)方法。
方法2:使用基類(lèi)
class Singleton(object): _instance = None def __new__(class_, *args, **kwargs): if not isinstance(class_._instance, class_): class_._instance = object.__new__(class_, *args, **kwargs) return class_._instance class MyClass(Singleton, BaseClass): pass
- 優(yōu)點(diǎn):是一個(gè)真正的類(lèi)。
- 缺點(diǎn):涉及多重繼承,
__new__
方法可能會(huì)在從第二個(gè)基類(lèi)繼承時(shí)被覆蓋,需要更多的思考。
方法3:使用元類(lèi)
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] # Python2 class MyClass(BaseClass): __metaclass__ = Singleton # Python3 class MyClass(BaseClass, metaclass=Singleton): pass
- 優(yōu)點(diǎn):是一個(gè)真正的類(lèi),自動(dòng)處理繼承問(wèn)題,合理使用了元類(lèi)的特性。
- 缺點(diǎn):相對(duì)復(fù)雜,可能會(huì)在序列化時(shí)出現(xiàn)問(wèn)題。
方法4:裝飾器返回同名類(lèi)
def singleton(class_): class class_w(class_): _instance = None def __new__(class_, *args, **kwargs): if class_w._instance is None: class_w._instance = super(class_w, class_).__new__(class_, *args, **kwargs) class_w._instance._sealed = False return class_w._instance def __init__(self, *args, **kwargs): if self._sealed: return super(class_w, self).__init__(*args, **kwargs) self._sealed = True class_w.__name__ = class_.__name__ return class_w @singleton class MyClass(BaseClass): pass
- 優(yōu)點(diǎn):是一個(gè)真正的類(lèi),自動(dòng)處理繼承問(wèn)題。
- 缺點(diǎn):創(chuàng)建每個(gè)新類(lèi)時(shí)可能會(huì)有開(kāi)銷(xiāo),
_sealed
屬性的作用不太明確,無(wú)法使用super()
調(diào)用基類(lèi)的同名方法。
方法5:使用模塊
將需要作為單例的類(lèi)和相關(guān)屬性、方法定義在一個(gè)模塊中,由于模塊只會(huì)被導(dǎo)入一次,因此模塊中的全局變量和函數(shù)可以作為單例使用。
# singleton.py class MyClass: def foo(self): pass my_singleton = MyClass()
# main.py from singleton import my_singleton my_singleton.foo()
- 優(yōu)點(diǎn):簡(jiǎn)單直接。
- 缺點(diǎn):不是懶加載的,模塊導(dǎo)入時(shí)就會(huì)創(chuàng)建實(shí)例。
核心代碼
以下是使用元類(lèi)實(shí)現(xiàn)單例模式的代碼示例:
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 Logger(metaclass=Singleton): pass logger1 = Logger() logger2 = Logger() print(logger1 is logger2) # 輸出: True
最佳實(shí)踐
- 使用元類(lèi):元類(lèi)是實(shí)現(xiàn)單例模式的推薦方法,它可以自動(dòng)處理繼承問(wèn)題,并且是一個(gè)真正的類(lèi)。
- 考慮使用模塊:如果單例模式的實(shí)現(xiàn)比較簡(jiǎn)單,且不需要懶加載,可以考慮使用模塊來(lái)實(shí)現(xiàn)。
常見(jiàn)問(wèn)題
- 序列化問(wèn)題:使用元類(lèi)實(shí)現(xiàn)的單例模式在序列化時(shí)可能會(huì)出現(xiàn)問(wèn)題,因?yàn)榉葱蛄谢瘯r(shí)不會(huì)調(diào)用
__call__
方法??梢允褂没?lèi)繼承和__new__
方法來(lái)解決這個(gè)問(wèn)題。 - 線程安全問(wèn)題:在多線程環(huán)境下,需要確保單例模式的實(shí)現(xiàn)是線程安全的。可以使用鎖機(jī)制來(lái)保證線程安全,例如在元類(lèi)的
__call__
方法中使用鎖。 __init__
方法多次調(diào)用問(wèn)題:在某些實(shí)現(xiàn)中,__init__
方法可能會(huì)被多次調(diào)用??梢允褂靡粋€(gè)標(biāo)志位來(lái)確保__init__
方法只被調(diào)用一次。
以上就是Python實(shí)現(xiàn)單例模式的最佳方法匯總的詳細(xì)內(nèi)容,更多關(guān)于Python單例模式實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
GPU狀態(tài)監(jiān)測(cè)?nvidia-smi?命令的用法詳解
這篇文章主要介紹了GPU狀態(tài)監(jiān)測(cè)?nvidia-smi?命令的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11python實(shí)現(xiàn)五子棋雙人對(duì)弈
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)五子棋雙人對(duì)弈,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Python爬取qq空間說(shuō)說(shuō)的實(shí)例代碼
這篇文章主要介紹了Python爬取qq空間說(shuō)說(shuō)的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-08-08在python中實(shí)現(xiàn)同行輸入/接收多個(gè)數(shù)據(jù)的示例
今天小編就為大家分享一篇在python中實(shí)現(xiàn)同行輸入/接收多個(gè)數(shù)據(jù)的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07python神經(jīng)網(wǎng)絡(luò)facenet人臉檢測(cè)及keras實(shí)現(xiàn)
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡(luò)facenet人臉檢測(cè)及keras實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05python3設(shè)計(jì)模式之簡(jiǎn)單工廠模式
這篇文章主要為大家詳細(xì)介紹了python3設(shè)計(jì)模式之簡(jiǎn)單工廠模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Python3 使用selenium插件爬取蘇寧商家聯(lián)系電話
這篇文章主要介紹了Python3 selenium爬取蘇寧商家聯(lián)系電話,此處使用了selenium插件 使用的是火狐瀏覽器 信息存儲(chǔ)到csv表格里面,需要的朋友可以參考下2019-12-12用Python的繪圖庫(kù)(matplotlib)繪制小波能量譜
這篇文章主要介紹了用Python的繪圖庫(kù)(matplotlib)繪制小波能量譜,代碼簡(jiǎn)單詳細(xì),思路清晰,需要的朋友可以參考下2021-04-04