Python中實作單例模式的常見方式有哪些

WBOY
發布: 2023-05-12 09:07:17
轉載
1033 人瀏覽過

Python 中實作單例模式的幾種常見方式

元類別(Metaclass):

class SingletonType(type):
    """
    单例元类。用于将普通类转换为单例类。
    """
    _instances = {}  # 存储单例实例的字典
    def __call__(cls, *args, **kwargs):
        """
        重写 __call__ 方法。用于创建和返回单例实例。
        """
        if cls not in cls._instances:  # 如果类还没有实例化过
            cls._instances[cls] = super().__call__(*args, **kwargs)  # 则创建新实例并存储在字典中
        return cls._instances[cls]  # 返回字典中的实例
class MyClass(metaclass=SingletonType):
    """
    单例类。使用元类 SingletonType 将其转换为单例类。
    """
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print(f"Hello, my name is {self.name}.")
# 创建 MyClass 的两个实例,应该是同一个对象
obj1 = MyClass("Alice")
obj2 = MyClass("Bob")
# 打印两个实例的内存地址,应该相同
print(hex(id(obj1)))  # 输出:0x7f8d94547a90
print(hex(id(obj2)))  # 输出:0x7f8d94547a90
# 调用两个实例的方法,输出应该相同
obj1.say_hello()  # 输出:Hello, my name is Alice.
obj2.say_hello()  # 输出:Hello, my name is Alice.
登入後複製

在上面的程式碼中,我們定義了一個名為SingletonType 的元類,並將其用作MyClass 的元類。在 SingletonType 類別中,我們維護了一個 _instances 字典,用於儲存每個類別的唯一實例。在 __call__() 方法中,我們檢查 _instances 字典,如果類別尚未擁有實例,則建立一個新實例並將其新增至 _instances 中。最後,我們傳回 _instances 中的實例。

MyClass 類別中,我們定義了一個帶有參數的建構函數,並且使用 metaclass 參數來指定 SingletonType 元類別。由於 MyClass 類別使用 SingletonType 元類,因此它具有單一例行為。在程式中,我們建立了 MyClass 的兩個實例 obj1obj2,然後列印它們的記憶體位址以驗證它們是否是同一個物件。最後,我們呼叫這兩個實例的方法,輸出應該相同。

裝飾器(Decorator):

def singleton(cls):
    """
    单例装饰器。用于将普通类转换为单例类。
    """
    instances = {}  # 存储单例实例的字典
    def get_instance(*args, **kwargs):
        """
        获取单例实例的方法。
        """
        if cls not in instances:  # 如果类还没有实例化过
            instances[cls] = cls(*args, **kwargs)  # 则创建新实例并存储在字典中
        return instances[cls]  # 返回字典中的实例
    return get_instance
@singleton
class MyClass:
    """
    单例类。使用装饰器 singleton 将其转换为单例类。
    """
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print(f"Hello, my name is {self.name}.")
# 创建 MyClass 的两个实例,应该是同一个对象
obj1 = MyClass("Alice")
obj2 = MyClass("Bob")
# 打印两个实例的内存地址,应该相同
print(hex(id(obj1)))  # 输出:0x7f8d94547a90
print(hex(id(obj2)))  # 输出:0x7f8d94547
登入後複製

在上面的程式碼中,我們定義了一個名為 singleton 的裝飾器函數。在 singleton 函數內部,我們建立了一個 instances 字典,用於儲存每個類別的唯一實例。然後,我們定義了一個名為 get_instance 的內部函數,用於取得單例實例。在 get_instance 函數中,我們檢查 instances 字典,如果類別尚未擁有實例,則建立一個新實例並將其新增至 instances 中。最後,我們傳回字典中的實例。

MyClass 類別上套用 @singleton 裝飾器,以將其轉換為單例類別。由於該裝飾器是針對類別進行操作的,因此它可以輕鬆地將任何普通類別轉換為單例類別。在程式中,我們建立了 MyClass 的兩個實例 obj1obj2,然後列印它們的記憶體位址以驗證它們是否是同一個物件。最後,我們呼叫這兩個實例的方法,輸出應該相同。

模組(Module):

# mymodule.py
class MyClass:
    """
    单例类。
    """
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print(f"Hello, my name is {self.name}.")
my_singleton = MyClass("Alice")  # 创建单例实例
登入後複製
# main.py
from mymodule import my_singleton
# 使用单例实例
my_singleton.say_hello()  # 输出:Hello, my name is Alice.
登入後複製

在上面的程式碼中,我們將MyClass 類別定義在一個獨立的模組mymodule.py 中,並在其中建立了一個單例實例my_singleton。然後,在另一個檔案main.py 中,我們從mymodule 模組中導入my_singleton 實例,並使用它來呼叫say_hello() 方法。

由於 Python 模組在首次導入時會自動執行,因此我們可以利用此特性來建立單例實例。在 mymodule.py 模組中,我們可以確保 my_singleton 只會被建立一次,並在程式的其他部分中共用它。

new 方法:

class MyClass:
    """
    单例类。
    """
    _instance = None  # 存储单例实例的类变量
    def __new__(cls, *args, **kwargs):
        """
        重写 __new__ 方法。用于创建和返回单例实例。
        """
        if cls._instance is None:  # 如果类还没有实例化过
            cls._instance = super().__new__(cls)  # 则创建新实例并存储在类变量中
        return cls._instance  # 返回类变量中的实例
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print(f"Hello, my name is {self.name}.")
# 创建 MyClass 的两个实例,应该是同一个对象
obj1 = MyClass("Alice")
obj2 = MyClass("Bob")
# 打印两个实例的内存地址,应该相同
print(hex(id(obj1)))  # 输出:0x7f8d94547a90
print(hex(id(obj2)))  # 输出:0x7f8d94547a90
# 调用两个实例的方法,输出应该相同
obj1.say_hello()  # 输出:Hello, my name is Alice.
obj2.say_hello()  # 输出:Hello, my name is Alice.
登入後複製

在上面的程式碼中,我們將MyClass 類別的建構子改為__new__() 方法,並使用_instance 類別變數來儲存單例實例。在 __new__() 方法中,我們檢查 _instance 變數,如果類別尚未擁有實例,則建立一個新實例並將其新增至 _instance 中。最後,我們傳回 _instance 中的實例。

在程式中,我們建立了MyClass 的兩個實例obj1obj2,然後列印它們的記憶體位址以驗證它們是否是同一個對象。最後,我們呼叫這兩個實例的方法,輸出應該相同。

無論使用哪種方法實作單例模式,都需要注意線程安全性和可擴展性等方面的問題。因此,在實際開發中,請仔細考慮自己的需求並選擇合適的實作方式。

以上是Python中實作單例模式的常見方式有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!