Python - 單例類別

你好,正在成長的程式設計師們!今天,我們將進入Python編程的精彩世界。我們的目的地是哪裡呢?那就是神秘的單例類別之地!如果這聽起來有點令人生畏,別擔心——我保證在這篇教程結束時,你將成為單例的大師。那麼,讓我們一起深入探討吧!

Python - Singleton Class

什麼是單例類別?

在我們開始編碼之前,先來了解什麼是單例類別。想像一下,你正在玩一個視頻遊戲,遊戲中只有一個你可以控制的玩家角色。不論你存檔和重新載入遊戲多少次,你始終控制著同一個角色。這基本上就是單例類別在編程中所做的事情——它保證了一個類別只有一個實例,並提供了一個全局訪問點。

在Python中創建單例類別

在Python中,有幾種方法可以創建單例類別。我們將探討兩種主要方法:使用__init____new__。但首先,讓我們看看我們為什麼可能需要一個單例類別。

為什麼使用單例?

當你想要確保你的程序中只有一個類別實例存在時,單例非常有用。這在以下情況下可能會幫助到:

  1. 管理全局狀態
  2. 協調系統中的操作
  3. 管理共享資源,例如數據庫連接

現在,讓我們捲起袖子開始編碼!

使用init

我們的第一種方法涉及使用__init__方法,當創建對象時會被調用。以下是我們如何使用__init__創建單例:

class Singleton:
_instance = None

def __init__(self):
if Singleton._instance is None:
Singleton._instance = self
else:
raise Exception("這個類別是單例!")

@staticmethod
def get_instance():
if Singleton._instance is None:
Singleton()
return Singleton._instance

# 使用方式
s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
print(s1 is s2)  # 輸出:True

# 這將引發異常
# s3 = Singleton()

讓我們來分解一下:

  1. 我們定義了一個類別變量_instance來保存我們的單一實例。
  2. __init__方法中,我們檢查是否已存在實例。如果不存在,我們創建一個。如果存在,我們引發一個異常。
  3. 我們提供了一個get_instance()方法來訪問我們的單例。此方法在不存在實例時創建一個實例,或者返回現有的實例。

當我們運行此代碼時,s1s2將是同一個實例。嘗試直接創建一個新實例(如s3 = Singleton())將引發一個異常。

使用new

現在,讓我們看看使用__new__的另一種方法。這個方法在創建新實例之前於__init__之前被調用。

class Singleton:
_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

# 使用方式
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # 輸出:True

這裡發生了什麼:

  1. 我們覆蓋了__new__方法,該方法負責創建並返回一個新實例。
  2. 如果_instance是None,我們使用super().__new__(cls)創建一個新實例。
  3. 我們總是返回_instance,無論它是新創建的還是已經存在的。

這個方法更簡潔,不需要分離的get_instance()方法。

比較這兩種方法

讓我們在下面的表格中比較這些方法:

方法 益處 缺點
__init__ - 更明確的控制
- 可以防止直接實例化
- 需要分離的get_instance()方法
- 稍微複雜一些
__new__ - 更簡潔
- 支援直接實例化
- 明確控制較少
- 對初學者來說可能較不直觀

這兩種方法都達到了同一個目標,因此選擇往往取決於個人偏好或專案的具体要求。

實際案例

最後,讓我們看看一個實際案例。假設我們正在創建一個遊戲,並希望確保只有一個玩家角色:

class PlayerCharacter:
_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.name = "英雄"
cls._instance.health = 100
cls._instance.level = 1
return cls._instance

def level_up(self):
self.level += 1
print(f"{self.name} 上升到等級 {self.level}!")

# 使用方式
player1 = PlayerCharacter()
player2 = PlayerCharacter()

print(player1.name)  # 輸出:英雄
print(player2.name)  # 輸出:英雄

player1.level_up()  # 輸出:英雄上升到等級 2!
print(player2.level)  # 輸出:2

在這個例子中,不論我們創建多少次PlayerCharacter,我們都會得到同一個實例。這確保了我們的遊戲中只有一個玩家角色,從而保持了遊戲的狀態一致性。

這就是單例類別的全部!你剛剛掌握了在Python中創建單例類別的藝術。請記住,像所有強大的工具一樣,明智地使用單例。它們在管理全局狀態或共享資源方面非常出色,但過度使用它們可能會使你的代碼難以測試和維護。

繼續練習,繼續編碼,最重要的是,繼續享受!直到下次,編程愉快!

Credits: Image by storyset