python實現單例模式


1、什么是單例模式:

  單例模式即一個類有且僅有一個實例

  先看下面一個例子:

    

  可以看到,我調用了兩次Marry實例化,得到的結果id是不同的,說明,兩次創建了兩個不同的Marry實例。

  所以如果我們想要讓類有且僅有一個實例,思路就是創建一個實例,后續再創建的時候,先判斷是否已經存在實例了,如果已經存在了,就直接引用之前創建的實例即可。

2、使用python實現單例模式

  方法一:這是最好理解的一種方法

  使用python模塊--------python模塊就是天然的單例模式。

  python模塊在第一次導入時,會生成 .pyc 文件,第二次導入時,會直接加載 .pyc 文件,而不會再次執行模塊代碼。所以我們可以將需要單例模式的類定義在一個模塊中。

  新建文件singleton.py

  在文件中實現如下方法:

    

  然后在需要使用實例的地方導入實例marry

  from singleton import marry

  看下面的測試結果,我多次導入了marry,打印id,發現他們是一樣的,說明Marry實例只創建了一次。

  

 

  方法二:使用__new__來實現

  要理解這種方式,首先需要知道,創建一個類的實例的過程,先執行了類的__new__方法(通常我們沒寫,是默認調用了object的__new__方法),實例化對象,然后再調用__init__方法對對象進行初始化。

  

  如上圖,我們在類Marry的__new__方法中,判斷了,如果Marry的實例對象已經存在,則直接返回,反之才創建對象。

  但是上面的這種方式會有一點問題,就是在多線程中會出現問題,如下:

 

  方法三:使用裝飾器實現單例模式

  

 

  方法四:使用元類

  首先需要理解什么是元類?下面來簡單介紹一下:

  元類就是可以創建類的類

  我們正常創建一個類的時候是這樣的:

  class Marry(Person):

    pass

  在創建Marry類的時候,python做了如下事情:

    1)在Marry中查找是否有__metaclass__這個屬性,如果有,那么python會在內存中通過__metaclass__創建一個名為Marry的類對象

    2)Marry中沒有找到__metaclass__屬性,則回去她的父類Person中查找,並嘗試用__metaclass__指定的方法創建一個Marry類對象

    3)如果任何一個父類中都沒有__metaclass__屬性,python會去模塊中搜索是否有__metaclass__的指定。

    4)如果以上都沒有,那么python會使用元類type來創建Marry

  我們要使用元類來實現單例模式,就是要自定義一個元類。

  自定義元類的目的,就是攔截類的創建,修改一些特性,然后再返回該類。聽起來是不是和裝飾器很相似?

  下面言歸正傳,看看通過元類來實現單例模式的代碼:

 1 class SingletonType(type):
 2     def __call__(cls,*args, **kwargs):# 這里的cls即是Marry類
 3         if not hasattr(cls, "_instance"):
 4             cls._instance = super(SingletonType, self).__call__(*args, **kwargs)#type的__call__方法會調用Marry的__new__方法創建對象,然后調用__init__初始化對象
 5         return cls._instance
 6 
 7 
 8 class Marry(metaclass=SingletonType):#指定Marry的type為SingletonType
 9     def __init__(self):
10         self.name = "marry"
11         self.age = 25
12 
13 marry1 = Marry()
14 marry2 = Marry()

上面通過元類的方式實現了單例模式,創建了兩個Marry實例,通過打印marry1和marry2的id,可以看到,他們的id是一樣的,說明他們是同一個實例。

簡單說一下上面元類實現單例模式的過程:

  1)類由type創建,創建類時,type的__init__會自動執行。類()執行type的__call__方法(即類的__new__方法和類的__init__方法)

  2)對象由類創建,創建對象時,類的__init__方法自動執行,對象()執行類的__call__方法

  再看上面的例子:

  1)創建類Marry時,指定了元類為SingletonType(metaclass=SingletonType),此時會自動執行元類的__init__方法,class SingletonType中我們沒有寫__init__,但是它繼承了type,所以它會自動執行type的__init__方法。

  2)實例化Marry(marry1=Marry())時,會去執行元類的__call__方法,在SingletonType的__call__方法中,我們判斷了cls是否已經包含了實例,如果已經包含了,直接返回類的實例,如果沒有包含,我們會調用type的__call__方法去創建實例。

  3)type的__call__方法中會調用cls的__new__方法去創建對象和__init__方法去初始化對象。

  4)如果我們給class Marry中加上__call__(cls, *args, **kwargs)方法,我們在調用實例marry1()的時候,會去調用Marry的__call__方法。

 

 

參考:https://www.cnblogs.com/huchong/p/8244279.html#navigator

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM