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
的兩個實例 obj1
和 obj2
,然後列印它們的記憶體位址以驗證它們是否是同一個物件。最後,我們呼叫這兩個實例的方法,輸出應該相同。
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
的兩個實例 obj1
和 obj2
,然後列印它們的記憶體位址以驗證它們是否是同一個物件。最後,我們呼叫這兩個實例的方法,輸出應該相同。
# 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
只會被建立一次,並在程式的其他部分中共用它。
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
的兩個實例obj1
和obj2
,然後列印它們的記憶體位址以驗證它們是否是同一個對象。最後,我們呼叫這兩個實例的方法,輸出應該相同。
無論使用哪種方法實作單例模式,都需要注意線程安全性和可擴展性等方面的問題。因此,在實際開發中,請仔細考慮自己的需求並選擇合適的實作方式。
以上是Python中實作單例模式的常見方式有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!