Python中的單例模式


在python中,我們可以用多種方法來實現單例模式:

  - 使用模塊

  - 使用__new__

  - 使用裝飾器

  - 使用元類(metaclass)

使用模塊

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

復制代碼
# mysingle.py class MySingle:
  def foo(self):
    pass

sinleton = MySingle()
將上面的代碼保存在文件mysingle.py中,然后這樣使用:
from mysingle import sinleton
singleton.foo()
復制代碼

當我們實現單例時,為了保證線程安全需要在內部加入鎖

 

import threading
class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        pass


    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls)  
        return Singleton._instance

 

 

 

使用__new__

為了使類只能出現一個實例,我們可以使用__new__來控制實例的創建過程,代碼如下:

復制代碼
class Singleton(object):
    def __new__(cls):
        # 關鍵在於這,每一次實例化的時候,我們都只會返回這同一個instance對象
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance
 
obj1 = Singleton()
obj2 = Singleton()
 
obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2
 
輸出結果:
value1  value1
復制代碼

使用裝飾器:

我們知道,裝飾器可以動態的修改一個類或函數的功能。這里,我們也可以使用裝飾器來裝飾某個類,使其只能生成一個實例:

復制代碼
def singleton(cls): instances = {} def getinstance(*args,**kwargs): if cls not in instances: instances[cls] = cls(*args,**kwargs) return instances[cls] return getinstance @singleton class MyClass: a = 1 c1 = MyClass() c2 = MyClass() print(c1 == c2) # True


在上面,我們定義了一個裝飾器 singleton,它返回了一個內部函數 getinstance
該函數會判斷某個類是否在字典 instances 中,如果不存在,則會將 cls 作為 key,cls(*args, **kw) 作為 value 存到 instances 中,
否則,直接返回 instances[cls]
復制代碼

使用metaclass(元類)

元類可以控制類的創建過程,它主要做三件事:

  - 攔截類的創建

  - 修改類的定義

  - 返回修改后的類

使用元類實現單例模式:

class Singleton2(type): def __init__(self, *args, **kwargs): self.__instance = None super(Singleton2,self).__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(Singleton2,self).__call__(*args, **kwargs) return self.__instance class Foo(metaclass=Singleton2): pass  #在代碼執行到這里的時候,元類中的__new__方法和__init__方法其實已經被執行了,而不是在Foo實例化的
時候執行。且僅會執行一次。 foo1 = Foo() foo2 = Foo() print (Foo.__dict__) #_Singleton__instance': <__main__.Foo object at 0x100c52f10> 存在一個私有屬性來保存屬性,而不會污染
Foo類(其實還是會污染,只是無法直接通過__instance屬性訪問) print (foo1 is foo2) # True


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM