Python單實例
#1 環境
Python3.8.1
#2 什麼是單實例
單例模式就是確保一個類只有一個實例.當你希望整個系統中,某個類只有一個實例時,單例模式就派上了用場
#3 實現單實例方式
#3.1 非單實例
class MyClass(object):
def foo(self):
return None
obj1 = MyClass()
obj2 = MyClass()
print(obj1 is obj2)
print(id(obj1))
print(id(obj2))
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sQaWZCJg-1582358419143)(https://raw.githubusercontent.com/Coxhuang/yosoro/master/20200221131107-image.png)]
#3.2 使用模塊
class MyClass(object):
def foo(self):
return None
obj = MyClass()
使用:
from singleton.mysingleton import obj
python的模塊就是天然的單例模式,因爲模塊在第一次導入的時候,會生成.pyc文件,當第二次導入的時候,就會直接加載.pyc文件,而不是再次執行模塊代碼.如果我們把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了
#3.3 使用裝飾器
def singleton(cls):
"""裝飾器函數"""
class_instance = {} # 定義一個接受實例的類
def singleton_inner(*args, **kwargs):
if cls not in class_instance: # 判斷該類是否被實例化過
class_instance[cls] = cls(*args, **kwargs) # 沒有被實例化過 -> 實例化 -> 將實例化的對象添加到字典中
return class_instance[cls] # 返回實例化對象
return singleton_inner
@singleton
class MyClass(object):
def foo(self):
return None
obj1 = MyClass()
obj2 = MyClass()
print(obj1 is obj2)
print(id(obj1))
print(id(obj2))
在類前加個裝飾器,在這裏裝飾器的目的只有一個,就是在類實例化前,先判斷這個類有沒有實例化過,如果沒有,則實例化,如果實例化過,測返回之前的實例化對象
#3.4 使用類
class MyClass(object):
def foo(self):
return None
@classmethod
def get_instance(cls, *args, **kwargs):
"""實例化函數"""
if not hasattr(cls, '_instance'):
cls._instance = cls(*args, **kwargs)
return cls._instance
obj1 = MyClass.get_instance()
obj2 = MyClass.get_instance()
print(obj1 is obj2)
print(id(obj1))
print(id(obj2))
obj3 = MyClass()
print(id(obj3))
以這種方式實現單實例,有兩個弊端:
- 只有MyClass.get_instance()這樣子實例化對象才能實現單實例,如果是使用MyClass()這種方式實例化,則不能實現單實例
- 多線程的時候,很可能會出現多個實例,因爲當調用這個類方法的時候get_instance(),如果在實例化過程中__init__函數消耗很長時間,那麼其他的線程的實例化,就會認爲自己是第一個實例化,這樣以來,就會導致出現多個實例
#3.5 重寫__new__方法(推薦)
class MyClass(object):
def foo(self):
return None
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls)
return cls._instance
obj1 = MyClass()
obj2 = MyClass()
print(obj1 is obj2)
print(id(obj1))
print(id(obj2))
一個對象的實例化過程是先執行類的__new__方法,如果我們沒有寫,默認會調用object的__new__方法,返回一個實例化對象,然後再調用__init__方法,對這個對象進行初始化,我們可以根據這個實現單例