1. 程式人生 > >python單例模式控制成只初始化一次,常規型的python單例模式在新式類和經典類中的區別。

python單例模式控制成只初始化一次,常規型的python單例模式在新式類和經典類中的區別。

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單例模式在新式類和經典類中的區別。