認識單例模式 __new__ __init__
阿新 • • 發佈:2018-12-04
讓類的例項在系統中只有一個唯一的例項,每一次執行 類名()返回 的物件,記憶體地址相同。
單例設計模式的使用場景:
音樂播放器物件
回收站物件
印表機物件
__new__ 的執行順序是在__init__之前,因為__new__執行的是類方法所以在__init__之前,__new__要先分配記憶體空間給物件,然後再把物件的引用給__init__方法。
class Singleton(object): def __init__(self,*args,**kwargs): print("__init__") @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): print("instance") Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance Singleton.instance(())
instance
__init__
class Musicplayer:
def __new__(cls, *args, **kwargs):
print("__new__")
def __init__(self):
print("__init__")
player1 = Musicplayer()
__new__
如果不把物件引用返回給__init__則只會執行__new__方法,所以把物件引用返回給__init__.
class Musicplayer: def __new__(cls, *args, **kwargs): print("__new__") return super().__new__(cls) def __init__(self): print("__init__") player1 = Musicplayer()
__new__
__init__
class Musicplayer:
def __init__(self):
print("播放器")
播放器
<__main__.Musicplayer object at 0x000002535AB0EB70>
播放器
<__main__.Musicplayer object at 0x000002535AB0EC50>
建立兩個Musicplayer的物件,他們的記憶體地址不一樣,說明建立了兩個播放器物件。
要想建立單例則必須重寫__new__方法。
要記住這個流程:
先判斷有之前有沒有建立例項物件,如果有則繼續用這個例項物件的記憶體的地址,沒有則在記憶體中開闢一個空間給這個第一次建立的例項物件。
class Musicplayer:
instance = None#物件
def __new__(cls, *args, **kwargs):
if cls.instance is None:#判斷類屬性是否為空物件
cls.instance = super().__new__(cls)#如果是空則呼叫父類方法,為第一個物件建立記憶體空間
return cls.instance#返回類屬性儲存的物件引用給__init__
def __init__(self):
print("播放器")
player1 = Musicplayer()
print(player1)
player2 = Musicplayer()
print(player2)
播放器
<__main__.Musicplayer object at 0x000002832CBEEC50>
播放器
<__main__.Musicplayer object at 0x000002832CBEEC50>
重寫__new__方法後,建立的物件都指向唯一一個記憶體地址。
單例只初始化一次:
就是在設定一個類屬性init_flag = False,在__init__方法下判斷init_Flag是否為True,如果是True則return Non,不是就執行第一次初始化的函式,在把init_flag = True。
class Musicplayer:
instance = None#
init_flag = False
def __new__(cls, *args, **kwargs):
if cls.instance is None:#判斷類屬性是否為空物件
cls.instance = super().__new__(cls)#如果是空則呼叫父類方法,為第一個物件建立記憶體空間
return cls.instance#返回類屬性儲存的物件引用給__init__
def __init__(self):
if Musicplayer.init_flag == True:
return
print("播放器")
Musicplayer.init_flag = True
播放器
<__main__.Musicplayer object at 0x0000029B8A67EC50>
<__main__.Musicplayer object at 0x0000029B8A67EC50>