1. 程式人生 > 實用技巧 >單例模式以及Python實現

單例模式以及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