1. 程式人生 > >Python_從零開始學習_(42) 單例

Python_從零開始學習_(42) 單例

目錄

 

1.  單例設計模式

2.  __new__方法

3.  Python 中的單例

 

1.  單例設計模式

  • 設計模式
  • 設計模式 是 前人工作的總結和提煉,  通常,  被人們廣泛流傳的設計模式都是針對 某一特定問題 的成熟解決方案
  • 使用 設計模式 是為了可重用程式碼,  讓程式碼更容易被他人理解,  保證程式碼可靠性
  • 單例設計模式
  • 目的 ---- 讓 類 建立的物件,  在系統中 只有 唯一的一個例項
  • 每一次執行 類名() 返回的物件,  記憶體地址是相同的

單例設計模式的應用場景

  • 音樂播放 物件
  • 回收站 物件
  • 印表機 物件
  • ......

 

2.  __new__方法

  • 使用 類名() 建立物件時,  Python 的直譯器 首先 會 呼叫 __new__方法為物件 分配空間
  • __new__ 是一個由 object 基類提供的 內建的靜態方法,  主要作用有兩個:
  • 1) 在記憶體中為物件 分配空間
  • 2) 返回 物件的引用
  • Python 的直譯器獲得物件的 引用 後,  將引用作為 第一個引數,  傳遞給 __init__ 方法

重寫 __new__ 方法 的程式碼非常固定!

  • 重寫 __new__ 方法 一定要 return super().__new__(cls)
  • 否則 Python 的直譯器 得不到 分配了空間的 物件引用,  就不會呼叫物件的初始化方法
  • 注意: __new__ 是一個靜態方法,  在呼叫時需要 主動傳遞 cls 引數

 

 3.  Python 中的單例

  • 單例  ---- 建立的物件,  在系統中 只有 唯一的一個例項
  1. 定義一個 類屬性,  初始值是 None , 用於記錄 單例物件的引用
  2. 重寫 __new__ 方法
  3. 如果 類屬性 is None , 呼叫父類方法分配空間,  並在類屬性中記錄結果
  4. 返回 類屬性 中記錄的 物件引用

 

class MusicPlayer(object):

    # 記錄第一個被建立物件的引用
    instance = None

    def __new__(cls, *args, **kwargs):

        # 1. 判斷類屬性是否是空物件
        if cls.instance is None:
            # 2. 呼叫父類的方法, 為第一個物件分配空間
            cls.instance = super().__new__(cls)

        # 3. 返回類屬性儲存的物件引用
        return cls.instance

 只執行一次初始化工作

  • 在每次只是用 類名() 建立物件時,  Python 的直譯器都會自動呼叫兩個方法:
  • __new__ 分配空間
  • __init__ 物件初始化
  • 每次建立物件都會呼叫一次初始化的方法

需求

  • 讓 初始化動作 只被 執行一次

解決辦法

  1. 定義一個類屬性 init_flag 標記是否 執行過初始化動作,  初始值為 False
  2. 在 __init__ 方法中,  判斷 init_flag ,  如果為 False 就執行初始化動作
  3. 然後將 init_flag 設定為 True 
  4. 這樣,  再次 自動 呼叫 __init__ 方法時, 初始化動作就不會被再次執行
class MusicPlayer(object):

    # 記錄第一個被建立物件的引用
    instance = None
    # 記錄是否執行過初始化方法
    init_flag = False

    def __new__(cls, *args, **kwargs):

        # 1. 判斷類屬性是否是空物件
        if cls.instance is None:
            # 2. 呼叫父類的方法, 為第一個物件分配空間
            cls.instance = super().__new__(cls)

        # 3. 返回類屬性儲存的物件引用
        return cls.instance

    def __init__(self):

        # 1. 判斷是否執行過初始化動作
        if MusicPlayer.init_flag:
            return

        # 2. 如果沒有執行過, 執行初始化動作
        print("初始化播放器")

        # 3. 修改類屬性的標記
        MusicPlayer.init_flag = True


# 建立多個物件
player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)