python單例模式控制成只初始化一次,常規型的python單例模式在新式類和經典類中的區別。
阿新 • • 發佈:2018-08-13
spa alt let __main__ python2 urn 時間 div 分享
單例模式的寫法非常多,但常規型的單例模式就是這樣寫的,各種代碼可能略有差異,但核心就是要搞清楚類屬性 實例屬性,就很容易寫出來,原理完全一模一樣。
如下:
源碼:
class A(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, ‘__inst‘): print(‘執行new‘) obj = super(A, cls).__new__(cls) setattr(cls, ‘__inst‘, obj)return obj else: return cls.__dict__[‘__inst‘] def __init__(self, x): print(‘執行init‘) self.x = x if __name__ == ‘__main__‘: a1 = A(1) print(‘a1.x ‘, a1.x) a2 = A(2) print(‘a2.x ‘, a2.x) print(‘a1.x ‘, a1.x) a3 = A.__new__(A) # a3.__init__(3) # a3 = A(3) 實際是調用了new和init方法,此處屏蔽調用init print(‘a3.x ‘, a3.x) print(id(a1), id(a2), id(a3))
實例化了三個對象,執行結果可以猜猜:
可以發現,執行了一次new,但執行了兩次init,這是在新式類下運行的,python3默認是新式類,不管有沒有繼承object。
如果是python2,且不繼承object,實際上是只會打印執行一次init。所以這是py2和py3的又一個區別,經典類和新式類區別非常多,新式類的反射方法也與經典類有些不同。但一般文章只說新式類和經典類的區別只是廣度優先和深度優先,誤導。
3、終極目標就是使python3的實例也不多執行力一次init,(因為雖然單例模式能控制成是所有類的實例指向同一個對象,但有時候的單例模式初始化是建立一個io連接或者資源池,這樣每次執行初始化浪費一些時間)
兩種方法,一種是增加一個類屬性做標誌,在init方法中增加if判斷
第二種是,不使用 a = A(xxxx),而使用a = A.__new__(A),因為a = A(xxxx),實際上是a = A.__new__(A),和a.__init__(xxx)
4、還有一種方式是使用裝飾器,如果按照這個寫法也不會執行多次init
#coding=utf8 from functools import wraps def singleton(cls): print cls instances = {} @wraps(cls) def getinstance(*args, **kw): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass(object): a = 1 m1=MyClass() m2=MyClass() print m1 is m2
python單例模式控制成只初始化一次,常規型的python單例模式在新式類和經典類中的區別。