單例模式
單例模式:不管用類實例化對象多少次,所得到的對象都是同一個對象。這種模式的應用場景,如數據庫連接,配置信息等。
1 通過類的嵌套實現單例
# create singleton by means of class nestification
class Singleton(object):
# really working class
class Wrapper_class(object):
def __init__(self, name):
self.name = name
def show_id(self):
return id(self)
def work(self):
print('i am working')
# save Wrapper_class instance
_instance = None
def __init__(self):
if Singleton._instance is None:
Singleton._instance = Singleton.Wrapper_class('wrapper')
# when get attribute if not exist, call this function. it return getattr function.
def __getattr__(self, item):
return getattr(self._instance, item)
# getattr include three params: instance name, attribute or method name, default value when instance not include attribute
if __name__ == '__main__':
a = Singleton()
b = Singleton()
print(a)
print(b)
print(a.show_id())
print(b.show_id())
以上代碼修改自實驗樓--python設計模式--單例。如有侵權請聯繫[email protected]
代碼解析:Wrapper_class類是真正幹活的類,它只進行一次實例化,並用Singleton類變量_instance保存,不管對Singleton類進行多少次實例化,內部由Wrapper_class類實例化出的幹活的對象就只有一個。
Singleton類的方法__getattr__作用是:當調用了Singleton類不存在的方法或者屬性時,就會運行Singleton的__getattr__方法。
return getattr(對象,屬性或方法) 作用:檢查屬性或方法是否屬於對象,屬於的話,調用這個方法或者對象。
本例中,調用了Singleton類實例化對象的show_id()方法,但Singleton類中並未實現這個方法,因此首先調用了Singleton類的__getattr__方法,並返回了getattr(self._instance, item)方法,這個方法首先檢查Wrapper_class類實例化的保存在_instance中的對象是否具有show_id()方法,正好Wrapper_class類中實現了這個方法,因此運行了這個方法,得到了結果
<__main__.Singleton object at 0x000002346197C358>
<__main__.Singleton object at 0x000002346197C550>
2423998891120
2423998891120
由結果知,不管實例化多少次Singleton類,但最終幹活的對象都是同一個2 裝飾器實現單例
利用類裝飾器實現單例
先上代碼吧
# create singleton by means of class decorator
class Decorator(object):
def __init__(self, cls):
self._cls = cls
def __call__(self, *args, **kwargs):
try:
return self._instance
except AttributeError:
self._instance = self._cls()
return self._instance
@Decorator
class Work(object):
def __init__(self):
pass
def show_id(self):
return id(self)
if __name__ == '__main__':
a = Work()
b = Work()
print(a.show_id())
print(b.show_id())
結果爲
1969722475520
1969722475520
上述代碼中,類Decorator是裝飾器類,其override了__call___方法,進行了custom。__call__方法使類Decorator實例化的對象可以像函數一樣被調用。因此可以當做裝飾器裝飾其他函數或類。只有可調用對象才能作爲裝飾器
對於用函數去裝飾函數這樣的簡單的裝飾器類型,很容易理解其中代碼的執行流程。但理解類裝飾類這種類型確實讓我頭疼。就比葫蘆畫瓢地理解吧。函數裝飾函數類型:裝飾後返回的是裝飾器內層的函數,然後替代原來的函數。那麼同理,用類去裝飾類,裝飾後返回的應該是裝飾器中的類的實例(別打臉,我猜的)。先就這樣理解吧。正如上面的例子。類Work被類Decorator裝飾,那麼裝飾後類Work就被傳遞進了Decorator的self._cls位置。然後把類Decorator的實例返回,並代替類Work的位置。當調用類Work進行實例化時,實際上調用的是裝飾過以後的類Decorator的實例。仔細觀察類Decorator的代碼,可知,首次創建的時候,會生成一個實例屬性self._instance。當第二次進行調用的時候,直接返回的是self._instance。因此就實現了單例模式。我對這段代碼還是有很多疑惑。真正懂的大神可以評論告訴我啊,小弟在這裏先謝過,有人說,這段代碼不能用於多線程,我沒試過,大家注意下
3 通過__new__方法實現單例
# crate singleton by means of __new__
class Singleton(object):
_instance = None # 一個下劃線開頭表示受保護的屬性
# __new__函數在調用__init__方法前調用,目的是創建一個對象,因此,其方法的第一個參數要傳遞類名,cls,而不是self
# 只有創建了對象後才能使用self
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
if __name__ == '__main__':
a = Singleton()
b = Singleton()
print(id(a), id(b))
結果爲
2025743751544 2025743751544