Python單例設計模式一

一、理解單例設計模式

單例模式提供這樣一個機制,即確保類有且只有一個特定類型的對象,並提供全局訪問點。因此,單例模式通常用於日誌記錄、數據庫操作、打印機後臺處理程序;該程序運行過程中只能生成一個實例,以避免對同一資源產生相互衝突的請求。由於在系統內存中只存在一個對象,因此可以節約系統資源,例如數據庫操作需要頻繁的創建和銷燬對象時單例模式無疑可以提高系統的性能。

單例設計模式的意圖:

① 確保類有且只有一個對象被創建

② 爲對象提供一個訪問點,以使程序可以全局訪問對象

③ 控制共享資源的並行訪問

實現單例模式的一個簡單方法是,使構造函數私有化,並創建一個靜態方法來完成對象的初始化。

利用Python實現經典的單例模式

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance


s = Singleton()
s1 = Singleton()
print(s)
print(s1)

 在上面的代碼中,我們通過覆蓋__new__方法來控制對象的創建。對象s就是由__new__方法創建的,但是在創建之前,該方法會檢查對象是否已存在。

方法hasattr(python的特殊方法,用來了解對象是否具有某個屬性)用於查看對象cls是否具有屬性instance,該屬性的作用是檢查該類是否已經生成了一個對象。當對象s1被請求的時候,hasattr()發現對象已經存在,所以,對象s1將被分配已有的對象實例

單例模式中的懶漢式實例化

在導入模塊的時候,我們可能無意中創建一個對象,但當時根本用不到它。懶漢式實例化能夠確保在實際需要時才創建對象。所以,懶漢式實例化是一種節約資源並僅在需要時才創建它們的方式。

class Singleton(object):
    __instance = None

    def __init__(self):
        if not Singleton.__instance:
            print('__init__ method called ..')
        else:
            print('Instance already created:', self.get_instance())

    @classmethod
    def get_instance(cls):
        if not cls.__instance:
            cls.__instance = Singleton()
        return cls.__instance


s = Singleton().get_instance()
s1 = Singleton().get_instance()
print(s)
print(s1)
print('....................')
s2 = Singleton()
s3 = Singleton()
print(s2)
print(s3)

在上面的代碼示例中,執行s = Singleton()的時候,它會調用__init__方法,但是沒有新的對象被創建。然而實際的對象創建發生在調用Singleton().get_instance()的時候,我們正是通過這種方式來實現懶漢式實例化的。

模塊級別的單例模式

默認情況下,所有的模塊都是單例,這是由Python的導入行爲所決定的。

python通過下列的方式來工作:

① 檢查一個python模塊是否已經導入

② 如果已經導入,則返回該模塊的對象,如果還沒有導入,則導入該模塊,並實例化

③ 因此,當模塊被導入的時候,它就會被初始化。然而,當同一個模塊被再次導入的時候,它不會再次初始化,因爲單例模式只能有一個對象,所以,它會返回同一個對象

Monostate單例模式

在GOF(設計模式)中的單例設計模式是指,一個類有且只有一個對象。通常程序員需要的是讓實例共享相同的狀態。開發人員應該關注狀態和行爲,而不是同一性。由於該概念及與所有對象共享相同的狀態,因此被稱爲單態模式。

Monostate 模式可以通過Python輕鬆實現,在下面的代碼中,我們將類變量__shared_state賦給了變量__dict__。Python使用__dict__存儲一個類所有對象的狀態。

class Borg(object):
    __shared_state = {"1": "2"}

    def __init__(self):
        self.x = 1
        self.__dict__ = self.__shared_state


b = Borg()
b1 = Borg()
b.x = 4
print("Borg Object b: ", b)
print("Borg Object b1: ", b1)
print("Object state b: ", b.__dict__)
print("Object state b1: ", b1.__dict__)

在上面的代碼中,我們把__shared_state賦給所有已經創建的實例。所以我們創建了兩個實例“b”和“b1”,我們得到了兩個不同的對象,這一點和單例模式是不同的,單例模式只能生成一個對象。然而對象的狀態即b.__dict__和b1.__dict__卻是相同的;就算對象b的變量x發生了變化,這個變化也會複製到所有對象共享的__dict__中

單例和元類

用來創建類的類就是元類。元類是一個類的類,意味着該類是它的元類的實例。使用元類,程序員有機會從預定義的Python類創建自己類型的類。例如,如果你有一個對象MyClass,你可以創建一個元類MyKls,它按照你需要的方式重新定義MyClass的行爲

類的定義是由它的元類決定,所以當我們用類A創建一個類時,Python通過A=type(name, bases, dict)創建它

name:這是類的名稱      bases:這是基類      dict: 這是屬性變量

現在如果有一個類有一個預定義的元類,那麼python就會通過A=MetaKls(name, bases, dict)來創建類;

下面python3中一個示例元類的實現:

class MyInt(type):
    def __call__(cls, *args, **kwargs):
        print("here's My int", args)
        print("想怎麼處理這個對象就怎麼處理")
        return type.__call__(cls, *args, **kwargs)


class Int(metaclass=MyInt):
    def __init__(self, x, y):
        self.x = x
        self.y = y


i = Int(4, 5)

對於已經存在的類來說,當需要創建對象時,將調用Python的特殊方法__call__。在上面的代碼中,當我們使用int(4,5)實例化int類時,MyInt元類的__call__方法將被調用,這意味着現在元類控制着對象的實例變化。

前面的思路同樣適用於單例設計模式。由於元類對類的創建和對象實例化有更多的控制權,所以它可以用於創建單例。(注意:爲了控制類的創建和初始化,元類將覆蓋__new__和__init__方法)

下面代碼基於元類的單例實現:

class MetaSingleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class Logger(metaclass=MetaSingleton):
    pass


log1 = Logger()
log2 = Logger()
print(log1, log2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章