單例模式指確保某個類在整個系統中只存在一個實例的一種設計模式
使用單例模式的好處:
1、每個實例都會佔用一定的內存資源,且初始化實例時會影響運行性能,所以當整個系統只需一個實例時,使用單例模式不僅可減少資源佔用,而且因爲只初始化一次,還可以加快運行性能。例如當程序通過一個類來讀取配置信息,而程序多個地方需要使用配置信息,這時整個程序運行過程中只需一個實例對象即可,可減少佔用內存資源,同時還可以保證程序在多處地方獲取的配置信息一致。
2、使用單例模式可進行同步控制,計數器同步、程序多處讀取配置信息這些情景下若只存在一個實例,即可保證一致性。
在python中,一般可使用一下4種方式實現單例模式:
1、通過模塊調用
2、使用__new__方法
3、使用裝飾器
4、使用元類(metaclass)
一、通過模塊調用
做法:將需要實現單例的類寫在模塊文件中,然後通過import引入該模塊,即可得到單例對象。
原理:在python3中,首次導入模塊文件時,會在程序目錄下的__pycache__目錄中生成pyc文件,之後再導入時,將直接加載pyc文件。從而實現單例。
實現代碼:
- module_demo.py
class singleton_cal: def foo(self): pass export_singleton = singleton_cal()
- use_module.py
from module_demo import export_singleton a = export_singleton from module_demo import export_singleton b = export_singleton print(a == b) print(id(a) == id(b))
可發現,多次調用/導入模塊,使用的都是同一個實例對象
二、使用__new__方法
_new__與_init__的區別:
__new\:創建實例對象時調用的構造方法
_init_:初始化方法,用於設置實例的相關屬性
python創建實例時,會先調用__new__構造方法,然後使用__init__進行實例初始化。
我們可以通過__new__來影響實例的創建,從而實現單例。
實現代碼:
- use_new.py
class Singleton(object):
__instance = None
def __new__(cls,*args,**kwargs):
if not cls. __instance:
cls.__instance = super().__new__(cls,*args,**kwargs)
return cls.__instance
a = Singleton()
b = Singleton()
print(a == b)
print(id(a) == id(b))
上面代碼中,聲明瞭一個私有類變量__instance,當__instance不爲None時,代表系統中已有實例,直接返回該實例,若__instance爲None時,表示系統中還沒有該類實例,則創建新實例並返回。
三、使用裝飾器
- use_decorator.py
from functools import wraps
def singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance
@singleton
class singleCls(object):
def foo(self):
pass
a = singleCls()
b = singleCls()
print(a == b)
print(id(a) == id(b))
只有當第一次調用singleCls時,裝飾器纔會從instances={}開始執行,之後調用singleCls時,都只執行getinstance函數,這是裝飾器的特性,利用這個特性,當我們多次調用singleCls時,在getinstance函數中判斷該類是否存在於instances字典中,若不存在,則創建該類實例並加入instances字典中,並返回字典中該類的實例;若存在,則直接返回字典中該類的實例。可利用該裝飾器爲多個類實現單例。
四、使用元類(metaclass)
元類創建了所有的類型對象(包括object對象),系統默認的元類是type。
實例,類,父類,元類的關係可表示爲下圖
元類中的__call方法,在已該類爲元類的類創建實例時調用,例如:類A以類B爲元類,當A創建實例時,B中的\call將會被調用。利用\call__可實現對實例創建的控制。
實現代碼:
- use_metaclass.py
class SingletonMeta(type):
__instance = None
def __call__(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance = type.__call__(cls,*args,**kwargs)
return cls.__instance
class myclass(metaclass = SingletonMeta):
def foo(self):
pass
a = myclass()
b = myclass()
print(a==b)
print(id(a)==id(b))
自定義元類時,通常繼承自type,聲明一個私有類變量__instance保存類實例,當__instance爲None時,調用type的__call__方法爲類創建實例,保存到__instance並返回;若__instance不爲None,則直接返回__instance,不重新創建實例。
歡迎掃碼關注公衆號“KeepCode”,分享更多技術好文,並提供技術電子書籍免費下載,每天進步一點點~~~~