python單例模式


一、單例模式

單例模式是應用開發過程中最簡單同時也是最著名的一種創建型設計模式。單例模式提供了一個類只有一個特定類型的對象的機制。

通常應用於場景為:日志記錄、數據庫操作等,程序運行時只能生成一個實例,避免對同一資源產生沖突的訪問請求。

二、如何設計單例模式

(1)重寫構造函數__new__方法

class Singleton(object):
    def __new__(self):
        if not hasattr(self,'instance'):
            self.instance = super(Singleton,self).__new__(self)
        return self.instance
        

a = Singleton()
b = Singleton()


print id(a),id(a)

  該方法主要思路就是在覆蓋實例化函數__new__(),在其中添加判斷,檢查對象是否存在。hasattr是python的特殊方法,用來查看對象是否具有某個屬性。

當然,如果想要繼承這個Singleton,子類中一定不要忘了重寫__new__方法,否則會覆蓋掉父類中已經修改的方法。

class Singleton(object):
    def __new__(self):
        if not hasattr(self,'instance'):
            self.instance = super(Singleton,self).__new__(self)
        return self.instance
        
class test(Singleton):
    def __new__(self):
        super(Singleton,self).__new__(self)
a = test()
b = test()


print id(a),id(a)

  

(2)元類編程重寫__call__方法

元類是一個類的類,可以通過創建元類,重新定義類的行為。當我們用類A創建一個類的時候,python通過A = type( name , bases , dict )創建它,其中name是類的名稱,base是基類,dict是屬性變量。

下面討論元類type構造類以及實例的過程:

class Meta(type):
    def __init__(self, name, bases, attrs):
        print "init"
        super(Meta, self).__init__(name, bases, attrs)
    def __new__(meta,name, bases, attrs):
        print "new"
        return super(Meta,meta).__new__(meta,name, bases, attrs)
    def __call__(self):
        print "call"
        return super(Meta,self).__call__()
        
        
s = ["Student", (object, ), {"name": "Joe", "age": 25}   ]    
ClassStudent = Meta(*s)
instance = ClassStudent()

  可以看到,結果是:

這個過程是,首先__new__創建類的實例,作為__init__的輸入,完成構造函數的作用。當然這個過程的結果是獲得了一個實例並且是叫做:

Student的類,ClassStudent是對這個類的引用。當采用()調用,即實現Meta的實例的可調用的實例化過程。

至此,我們簡單了解了相關的魔術函數的作用。

 

通過元類實現單例模式的方法為:

class Meta(type):
    _instance = {}
    def __init__(self, name, bases, attrs):
        print "init"
        super(Meta, self).__init__(name, bases, attrs)
    def __new__(meta,name, bases, attrs):
        print "new"
        return super(Meta,meta).__new__(meta,name, bases, attrs)
    def __call__(self):
        print "call"
        
        if self not in self._instance:
            self._instance[self] = super(Meta,self).__call__()
        return self._instance[self]
        
        
s = ["Student", (object, ), {"name": "Joe", "age": 25}   ]    
ClassStudent = Meta(*s)
instance1 = ClassStudent()
instance2 = ClassStudent()
print id(instance1),id(instance2)

  至此,可以看到,通過元類編程實現單例模式,需要改的是__call__函數,因為其構造函數是為了構造類的,而不是在生成實例的過程中,通過函數調用的方式生成實例會調用__call__,因此在這個位置操作。

 當然,對於單例類的使用,可以在類中通過__metaclass__屬性來設置,取代用type類直接生成的方法。

class Meta(type):
    _instance = {}
    def __init__(self, name, bases, attrs):
        print "init"
        super(Meta, self).__init__(name, bases, attrs)
    def __new__(meta,name, bases, attrs):
        print "new"
        return super(Meta,meta).__new__(meta,name, bases, attrs)
    def __call__(self):
        print "call"
        
        if self not in self._instance:
            self._instance[self] = super(Meta,self).__call__()
        return self._instance[self]
 

class ClassStudent(object):
    __metaclass__ = Meta
    pass
       
instance1 = ClassStudent()
instance2 = ClassStudent()
print id(instance1),id(instance2)

  當用戶定義一個類class的時候,Python解釋器就會在當前類中查找"__metaclass__"屬性,如果找到,就通過該屬性對應的代碼創建類;如果沒有找到,就繼續以相同的規則查找父類。如果在任何父類中都找不到"__metaclass__",就會用內置的type來創建類對象。

當然對於python3來說,添加了新的聲明單例的方法:

class Test(metaclass = MyMeta):
    pass

  

三、Monostate模式

對於上述單例模式,關注的是生成單一的實例,而通常程序員需要的是讓實例共享相同的狀態,因此,有時候需要關注狀態和行為,而不是同一性。這種概念即為Monostate(單態)模式。python實現這個模式的過程較為輕松:

class ClassStudent(object):
    _age = 20
    pass
       
instance1 = ClassStudent()
instance2 = ClassStudent()
print id(instance1),id(instance2)
print instance1._age,instance2._age

  可以看到,雖然不是一個實例,但是狀態相同。

 


免責聲明!

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



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