單例模式以及Python實現

單例模式:
就是確保一個類只有一個實例.當你希望整個系統中,某個類只有一個實例時,單例模式就派上了用場。

比如,某個服務器的配置信息存在在一個文件中,客戶端通過AppConfig類來讀取配置文件的信息.
如果程序的運行的過程中,很多地方都會用到配置文件信息,則就需要創建很多的AppConfig實例,
這樣就導致內存中有很多AppConfig對象的實例,造成資源的浪費.其實這個時候AppConfig我們希望它只有一份,就可以使用單例模式。

實現單例模式的幾種方法

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



 

2. 使用裝飾器
裝飾器裏面的外層變量定義一個字典,裏面存放這個類的實例.當第一次創建的收,就將這個實例保存到這個字典中.
然後以後每次創建對象的時候,都去這個字典中判斷一下,如果已經被實例化,就直接取這個實例對象.如果不存在就保存到字典中.
def singleton(cls):
    # 單下劃線的作用是這個變量只能在當前模塊裏訪問,僅僅是一種提示作用
    # 創建一個字典用來保存類的實例對象
    _instance = {}

    def _singleton(*args, **kwargs):
        # 先判斷這個類有沒有對象
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)  # 創建一個對象,並保存到字典當中
        # 將實例對象返回
        return _instance[cls]

    return _singleton

@singleton
class A(object):
    a = 1

    def __init__(self, x=0):
        self.x = x
        print('這是A的類的初始化方法')

a1 = A(2)
a2 = A(3)
print(id(a1), id(a2))

3.使用類
思路就是,調用類的instance方法,這樣有一個弊端就是在使用類創建的時候,並不是單例了.也就是說在創建類的時候一定要用類裏面規定的方法創

class Singleton(object):
    def __init__(self,*args,**kwargs):
        pass

    @classmethod
    def get_instance(cls, *args, **kwargs):
        # 利用反射,看看這個類有沒有_instance屬性
        if not hasattr(Singleton, '_instance'):
            Singleton._instance = Singleton(*args, **kwargs)

        return Singleton._instance

s1 = Singleton()  # 使用這種方式創建實例的時候,並不能保證單例
s2 = Singleton.get_instance()  # 只有使用這種方式創建的時候纔可以實現單例
s3 = Singleton()
s4 = Singleton.get_instance()

print(id(s1), id(s2), id(s3), id(s4))
4.基於__new__方法實現的單例模式(推薦使用,方便)
知識點:
1> 一個對象的實例化過程是先執行類的__new__方法,如果我們沒有寫,默認會調用object的__new__方法,返回一個實例化對象,然後再調用__init__方法,對這個對象進行初始化,我們可以根據這個實現單例.
2> 在一個類的__new__方法中先判斷是不是存在實例,如果存在實例,就直接返回,如果不存在實例就創建.
import threading
class Singleton(object): _instance_lock = threading.Lock() def __init__(self, *args, **kwargs): pass def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): with Singleton._instance_lock: if not hasattr(cls, '_instance'): Singleton._instance = super().__new__(cls) return Singleton._instance obj1 = Singleton() obj2 = Singleton() print(obj1, obj2) def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task, args=[i, ]) t.start()

參考:https://www.jianshu.com/p/6a1690f0dd00
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章