# python 單例模式 單例模式是一種設計模式,目的是確保一個類只有一個實例,並提供一個全局訪問點來獲取該實例。 有些類只需要一個全局唯一的實例,例如資料庫連接池、線程池、日誌記錄器等。使用單例模式可以確保這些類只有一個實例存在,從而避免了資源的浪費和不一致的狀態。 單例模式通常包含以下幾個要素 ...
python 單例模式
單例模式是一種設計模式,目的是確保一個類只有一個實例,並提供一個全局訪問點來獲取該實例。
有些類只需要一個全局唯一的實例,例如資料庫連接池、線程池、日誌記錄器等。使用單例模式可以確保這些類只有一個實例存在,從而避免了資源的浪費和不一致的狀態。
單例模式通常包含以下幾個要素:
-
私有化構造方法:將類的構造方法私有化,使得外部無法直接實例化該類。
-
靜態實例變數:在類中定義一個靜態變數,用來保存類的唯一實例。
-
全局訪問點:提供一個全局的靜態方法或屬性,用來獲取類的唯一實例。通過該訪問點,可以在任何需要使用該實例的地方獲取到單例對象。
示例代碼如下:
class A(object):
_instance = None
def __new__(cls, *args, **kw):
if not cls._instance:
cls._instance = super(A, cls).__new__(cls, *args, **kw)
return cls._instance
這段代碼定義了一個名為 Conf
的類,它實現了單例模式,並且在多線程環境下保證線程安全。
解釋
__new__函數
__new__
函數在 Python 中創建並返回一個對象實例,在對象創建之前被調用,用來控制對象的創建過程。
__new__
方法的定義形式如下:
def __new__(cls, *args, **kwargs):
# 實現代碼
return object.__new__(cls)
cls
參數代表要創建的類本身,*args
和 **kwargs
是用來傳遞給類的構造方法的參數。
__new__
方法的作用是創建並返回一個類的實例。可以在對象實例化之前對對象進行定製化的操作。通常情況下不會直接重寫 __new__
方法,而是在類的構造方法 __init__
中進行對象的初始化和屬性賦值。
__new__
方法通常用於以下情況:
- 當需要控制對象的創建過程,或者需要返回一個不可變的對象時,可以重寫
__new__
方法。 - 當需要自定義類的實例化過程,或者需要改變實例化的行為時,可以重寫
__new__
方法。
實現過程
-
A類中定義了一個類變數
_instance
,用來保存類的唯一實例。該變數在類的作用域內是全局唯一的。 -
在
__new__
方法中,首先判斷_instance
是否已經存在實例。如果不存在,則通過調用super(A, cls).__new__(cls, *args, **kw)
創建一個新的實例,並將其賦值給_instance
。這樣第一次調用__new__
方法時會創建一個新的實例,並將其賦給_instance
。從第二次開始的調用,由於_instance
已經存在實例,就直接返回該實例。 -
無論是創建了新的實例還是直接返回已存在的實例,都會將實例返回。無論多少次調用該類的構造方法,都只會返回同一個實例,實現了單例模式。因為
_instance
是一個類變數,所以它在類的所有實例之間是共用的,保證了只有一個實例被創建和返回。 -
這段代碼還加入了線程安全的考慮。因為在多線程環境下,可能會有多個線程同時調用該類的構造方法。為了保證線程安全,通過檢查
cls._instance
是否已經存在實例,可以避免多個線程同時創建實例的情況,從而保證了線程安全性。
擴展
上面的 cls 可以換成 self 嗎
在 __new__
方法中,cls
是一個約定俗成的參數名,代表當前類本身。雖然可以將 cls
替換為 self
,但這是不推薦的做法,因為 self
通常用於表示實例對象,而不是類對象。
在 __new__
方法中,cls
參數的作用是指明要創建的類。當調用一個類的構造方法時,會自動將類作為第一個參數傳遞給構造方法,通常我們將該參數命名為 self
。
而在 __new__
方法中,由於還沒有實例化對象,所以無法使用 self
來表示對象實例。因此使用 cls
來代表要創建的類本身。
cls 和 self 的區別
- cls:cls 是一個約定俗成的參數名,表示類本身。它在類方法(class method)中使用,用於引用類的屬性或調用類的方法。cls 通常作為第一個參數傳遞給類方法,以區分它與實例方法的不同。通過 cls,我們可以在類方法中訪問類的靜態成員或創建新的類實例。
class MyClass:
@classmethod
def class_method(cls):
print("This is a class method")
MyClass.class_method() # 調用類方法
- self: self 也是一個約定俗成的參數名,表示類的實例本身。它在實例方法(instance method)中使用,用於引用實例的屬性或調用實例的方法。self 作為第一個參數傳遞給實例方法,以便在方法內部訪問實例的成員。
class MyClass:
def __init__(self, name):
self.name = name
def instance_method(self):
print("My name is", self.name)
obj = MyClass("John")
obj.instance_method() # 調用實例方法
使用場景舉例
cls 在類方法中使用,用於引用類的屬性或調用類的方法。它通常用於在類方法內部訪問類級別的屬性或創建新的類實例。
class MyClass:
class_attribute = "Class Attribute"
@classmethod
def class_method(cls):
print(cls.class_attribute) # 訪問類級別的屬性
MyClass.class_method() # 調用類方法
print(MyClass.class_attribute) # 直接訪問類級別的屬性
self在實例方法中使用,用於引用實例的屬性或調用實例的方法。它通常用於在實例方法內部訪問實例級別的屬性或調用其他實例方法。
class MyClass:
def __init__(self):
self.instance_attribute = "Instance Attribute"
def instance_method(self):
print(self.instance_attribute) # 訪問實例級別的屬性
obj = MyClass()
obj.instance_method() # 調用實例方法
print(obj.instance_attribute) # 訪問實例級別的屬性