單例模式以及Python實現
阿新 • • 發佈:2020-12-28
單例模式:
就是確保一個類只有一個例項.當你希望整個系統中,某個類只有一個例項時,單例模式就派上了用場。
比如,某個伺服器的配置資訊存在在一個檔案中,客戶端通過AppConfig類來讀取配置檔案的資訊. 如果程式的執行的過程中,很多地方都會用到配置檔案資訊,則就需要建立很多的AppConfig例項, 這樣就導致記憶體中有很多AppConfig物件的例項,造成資源的浪費.其實這個時候AppConfig我們希望它只有一份,就可以使用單例模式。
其實,python的模組就是天然的單例模式,因為模組在第一次匯入的時候,會生成.pyc檔案,當第二次匯入的時候,就會直接載入.pyc檔案,而不是再次執行模組程式碼.如果我們把相關的函式和資料定義在一個模組中,就可以獲得一個單例物件了.
2. 使用裝飾器
裝飾器裡面的外層變數定義一個字典,裡面存放這個類的例項.當第一次建立的收,就將這個例項儲存到這個字典中.
然後以後每次建立物件的時候,都去這個字典中判斷一下,如果已經被例項化,就直接取這個例項物件.如果不存在就儲存到字典中.
知識點:
1> 一個物件的例項化過程是先執行類的
2> 在一個類的
比如,某個伺服器的配置資訊存在在一個檔案中,客戶端通過AppConfig類來讀取配置檔案的資訊. 如果程式的執行的過程中,很多地方都會用到配置檔案資訊,則就需要建立很多的AppConfig例項, 這樣就導致記憶體中有很多AppConfig物件的例項,造成資源的浪費.其實這個時候AppConfig我們希望它只有一份,就可以使用單例模式。
實現單例模式的幾種方法
1. 使用模組其實,python的模組就是天然的單例模式,因為模組在第一次匯入的時候,會生成.pyc檔案,當第二次匯入的時候,就會直接載入.pyc檔案,而不是再次執行模組程式碼.如果我們把相關的函式和資料定義在一個模組中,就可以獲得一個單例物件了.
裝飾器裡面的外層變數定義一個字典,裡面存放這個類的例項.當第一次建立的收,就將這個例項儲存到這個字典中.
然後以後每次建立物件的時候,都去這個字典中判斷一下,如果已經被例項化,就直接取這個例項物件.如果不存在就儲存到字典中.
def singleton(cls):
# 單下劃線的作用是這個變數只能在當前模組裡訪問,僅僅是一種提示作用
# 建立一個字典用來儲存類的例項物件
_instance = {}
def _singleton(*args, **kwargs):
# 先判斷這個類有沒有物件
if cls not in _instance:
_instance[cls] = cls(*args, **kwargs) # 建立一個物件,並儲存到字典當中
# 將例項物件返回
return _instance[cls]
return _singleton
@singleton
class A(object):
a = 1
def __init__(self, x=0):
self.x = x
print('這是A的類的初始化方法')
a1 = A(2)
a2 = A(3)
print(id(a1), id(a2))
3.使用類
思路就是,呼叫類的instance方法,這樣有一個弊端就是在使用類建立的時候,並不是單例了.也就是說在建立類的時候一定要用類裡面規定的方法創
class Singleton(object):
def __init__(self,*args,**kwargs):
pass
@classmethod
def get_instance(cls, *args, **kwargs):
# 利用反射,看看這個類有沒有_instance屬性
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
s1 = Singleton() # 使用這種方式建立例項的時候,並不能保證單例
s2 = Singleton.get_instance() # 只有使用這種方式建立的時候才可以實現單例
s3 = Singleton()
s4 = Singleton.get_instance()
print(id(s1), id(s2), id(s3), id(s4))
4.基於__new__
方法實現的單例模式(推薦使用,方便)知識點:
1> 一個物件的例項化過程是先執行類的
__new__方法
,如果我們沒有寫,預設會呼叫object的__new__
方法,返回一個例項化物件,然後再呼叫__init__方法
,對這個物件進行初始化,我們可以根據這個實現單例.2> 在一個類的
__new__方法中
先判斷是不是存在例項,如果存在例項,就直接返回,如果不存在例項就建立.
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self, *args, **kwargs):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
with Singleton._instance_lock:
if not hasattr(cls, '_instance'):
Singleton._instance = super().__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task, args=[i, ])
t.start()
參考:https://www.jianshu.com/p/6a1690f0dd00