1. 程式人生 > >認識單例模式 __new__ __init__

認識單例模式 __new__ __init__

讓類的例項在系統中只有一個唯一的例項,每一次執行 類名()返回 的物件,記憶體地址相同。

單例設計模式的使用場景:

音樂播放器物件

回收站物件

印表機物件

 

 

__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>