Python單例模式實現

Python單例模式實現

  單例模式是一種常用的軟件設計模式,該模式的主要問題是確保某一個類只有一個實例存在。有時候再項目中難免需要一些全局唯一的對象,這些對象大多是一些工具性的東西,在python中實現單例模式大概有如下幾種方法:
-類裝飾器
-使用元類或者__call__
-使用__new__
-使用模塊

1、使用類裝飾器

使用裝飾器實現單例類的時候,類本身並不知道自己是單例的,所以寫代碼的人可以不關心這個,只要正常寫自己的類的實現就可以了,類的單例有裝飾器保證。

def singleton(cls):
    instances = {}
    def _wrapper(*args,**kwargs):
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
            return instances[cls]
    return _wrapper

你會發現singleton裝飾器內部使用了一個dict,當然你也可以用其他的方式,不過一下的實現是錯誤的:

def singleton(cls):
    _instance = None #外部作用域的引用對於嵌套的內部作用域是隻讀的
    def _wrapper(*args,**kwargs):
        if _instance is None:#解釋器會拋出"UnboundLocalError: ...referenced before assignment"
            _instance = cls(*args,**kwargs)#賦值幸會將使解釋器將"_instance"看做局部變量
        return _instance
    return _wrapper


2、使用元類(__metaclass__)和可調用對象(__call__)

  python的對象系統中一切皆對象,可以稱之爲”類型對象”,比較繞,但是仔細想想也不難。類本身也是一種對象,只不過這種對象很特殊,它表示某一種類型。是對象,那必然是實例化來的,那麼誰實例化後是這種類型對象呢?答案就是元類。
  python中,class關鍵字表示定義一個類對象,此時解釋器會按照一定的規則尋找__metaclass__,如果找到了, 就調用對應的元類來實例化該類對象。如果沒有找到,就會調用type元類來實例化該對象。
  __call__是python的魔法方法,Python的面向對象是”Duck Type”的,意味着對象的行爲可以通過實現協議來實現,可以看作是一種特殊的接口形式。某個類實現了__call__方法意味着該類的對象是可調用的。可以像函數調用那樣。再考慮一下foo = Foo()這種實例化的形式,是不是很像。結合元類的概念,可以看出,Foo類是單例的,則在調用Foo()的時候每次都返回了同樣的對象。而Foo作爲一個類對象是單例的,意味着它的類(即生成它的元類)是實現了__call__方法的。所以可以如下實現:

class SingleTon(type):
    def __init__(cls,name,bases,attrs):
        super(SingleTon,cls).__init__(name,bases,attrs)
        cls._instance = None
    def __call__(cls,*args,**kwargs):
        if cls._instance is None:
        #以下不要使用"cls._instance(*args,**kwargs)",防止死循環,cls的調用行爲已經被當前的'__call__'協議攔截了,使用super(SingleTon,cls).__call__來生成cls的實例。
            cls._instance = super(SingleTon,cls).__call__(*args,**kwargs)
    return cls._instance

class Foo(object):#單例類
    \__metaclass__ = SingleTon

測試:

>>>a = Foo()
>>>b = Foo()
>>>a is b
>>>True
>>>a.x = 1
>>>b.x
>>>1


3、使用__new__

  __init__不是Python對象的構造方法,__init__只負責初始化實例對象,在調用__init__方法之前,會首先調用__new__方法生成對象,可以認爲__new__方法充當了構造函數的角色。所以可以在__new__中加以控制,使得某個類只能生成唯一對象。具體實現時可以實現一個父類,重載__new__方法,單例類只需要繼承這個父類就好。

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

class Foo(SingleTon):#單例類
    pass    



4、與實現3類似,採用單獨的類

class Foo(object):
    _instance = None
    def __new__(cls,*args,**kwargs):
    #實現__new__方法,_instance表示該類的實例,在生成對象實例的時候先判斷是否已經生成了該對象,如果沒有則生成該對象實例,有則返回該實例對象。
        if _instance is None:
            _instance = super(Foo,cls).__new__(cls,*args,**kwargs)
        return _instance


使用模塊
其實python的模塊就是天然的單例,因爲模塊在第一次導入時,會生成.pyc文件,當第二次導入時,就會直接加載.pyc,而不會再次執行模塊代碼。因此,我們只需要把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。如果我們真的需要一個單例類,可以考慮這樣做:

#mysingleton.py
class MySingleTon(object):
    def foo(self):
        pass

my_singleton = MysingleTon()    

將上面的代碼保存在mysingleton.py中,然後就可以這樣使用:

from mysingleton import my_singleton
my_singleton.foo()


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