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))
複制
#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__方法,對這個對象進行初始化,我們可以根據這個實作單例