本文主要包含以下內(nèi)容:
- 使用場景
- 一個(gè)較好的實(shí)現(xiàn)方式
使用場景
單例模式的主要目的就是確保某一個(gè)類只有一個(gè)實(shí)例存在椭豫。當(dāng)你希望在整個(gè)系統(tǒng)中,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí),單例對(duì)象就能派上用場赏酥。如:
- 當(dāng)每個(gè)實(shí)例都會(huì)占用資源喳整,并且不需要維護(hù)每個(gè)實(shí)例的狀態(tài),而且實(shí)例初始化會(huì)影響性能:某個(gè)服務(wù)器程序的配置信息存放在一個(gè)文件中裸扶,客戶端通過一個(gè) AppConfig 的類來讀取配置文件的信息框都。如果在程序運(yùn)行期間,有很多地方都需要使用配置文件的內(nèi)容呵晨,也就是說魏保,很多地方都需要?jiǎng)?chuàng)建 AppConfig 對(duì)象的實(shí)例,這就導(dǎo)致系統(tǒng)中存在多個(gè) AppConfig 的實(shí)例對(duì)象摸屠,而這樣會(huì)嚴(yán)重浪費(fèi)內(nèi)存資源谓罗,尤其是在配置文件內(nèi)容很多的情況下。事實(shí)上季二,類似 AppConfig 這樣的類檩咱,我們希望在程序運(yùn)行期間只存在一個(gè)實(shí)例對(duì)象。
- 當(dāng)有同步需要的時(shí)候胯舷,可以通過一個(gè)實(shí)例來進(jìn)行同步控制:Python的logger刻蚯,網(wǎng)站計(jì)數(shù)器
一個(gè)較好的實(shí)現(xiàn)方式
這里就不采用裝飾器的模式了,而是采用python的特性__new__
需纳,更加通俗易懂芦倒。
__new__
:是在新式類中新出現(xiàn)的方法艺挪,它作用在構(gòu)造方法建造實(shí)例之前不翩,可以這么理解,在 Python 中存在于類里面的構(gòu)造方法__init__()
負(fù)責(zé)將類的實(shí)例化麻裳,而在__init__()
啟動(dòng)之前口蝠,__new__()
決定是否要使用該__init__()
方法,因?yàn)?code>__new__() 可以調(diào)用其他類的構(gòu)造方法或者直接返回別的對(duì)象來作為本類的實(shí)例津坑。
上述總結(jié)下來就是__new__()
會(huì)在__init__()
實(shí)例化之前調(diào)用妙蔗,所以可以在實(shí)例化之前判斷該實(shí)例是否存在。
singleton.py
import threading
# 由于__new__是新式類出現(xiàn)的方法疆瑰,所以使用python2時(shí)需要采用新式類的創(chuàng)建方式眉反,python3隨意
# python2: class Singleton: ×
# class Singleton(object): √
class Singleton(object):
# 使用 threading.Lock() 來鎖住線程,避免多個(gè)線程同時(shí)操作而創(chuàng)建多個(gè)實(shí)例
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
# 雙重檢查穆役,提升效率
if not hasattr(Singleton, '_instance'):
# with ... -> _instance_lock.acquire() _instance_lock.release()
with Singleton._instance_lock:
if not hasattr(Singleton, '_instance'):
Singleton._instance = object.__new__(cls)
return Singleton._instance
if __name__ == '__main__':
def task():
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task)
t.start()
time.sleep(5)
obj = Singleton()
print(obj)
參考:
Python中的單例模式的幾種實(shí)現(xiàn)方式的及優(yōu)化
設(shè)計(jì)模式(Python)-單例模式
Python 之 new() 方法與實(shí)例化