1. 程式人生 > >Python 中的單例模式

Python 中的單例模式

1.什麼是單例模式 單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個例項存在。當你希望在整個系統中,某個類只能出現一個例項時,單例物件就能派上用場。單例模式能控制一個類只能產生一個物件。 2.為什麼需要單例模式
  • 當每個例項都會佔用資源,而且例項初始化會影響效能,這個時候就可以考慮使用單例模式,它給我們帶來的好處是隻有一個例項佔用資源,並且只需初始化一次;
  • 當有同步需要的時候,可以通過一個例項來進行同步控制,比如對某個共享檔案(如日誌檔案)的控制,對計數器的同步控制等,這種情況下由於只有一個例項,所以不用擔心同步問題。
3.單例模式應用場景
  • Python的logger就是一個單例模式,用以日誌記錄
  • Windows的資源管理器是一個單例模式
  • 執行緒池,資料庫連線池等資源池一般也用單例模式
  • 網站計數器
4.在 Python 中,實現單例模式的四種方式
  • 使用模組
  • 使用 __new__
  • 使用裝飾器(decorator)
  • 使用元類
4.1 使用模組     Python 的模組就是天然的單例模式,因為模組在第一次匯入時,會生成 .pyc 檔案,當第二次匯入時,就會直接載入 .pyc 檔案,而不會再次執行模組程式碼。因此,我們只需把相關的函式和資料定義在一個模組中,就可以獲得一個單例物件了。
如果我們真的想要一個單例類,可以考慮這樣做:
# mysingleton.py 
class My_Singleton(object): 
    def foo(self): 
        pass 
my_singleton = My_Singleton()

將上面的程式碼儲存在檔案 mysingleton.py 中,然後這樣使用:

from mysingleton import my_singleton
my_singleton.foo()
4.2 使用裝飾器     裝飾器維護一個字典物件instances,快取了所有單例類,只要單例不存在則建立,已經存在直接返回該例項物件。 我們定義一個裝飾器 singleton,它返回了一個內部函式 wrapper
,該函式會判斷某個類是否在字典 instances 中,如果不存在,則會將 cls 作為 key,cls(*args, **kw) 作為 value 存到 instances 中,否則,直接返回 instances[cls]。 使用裝飾器實現單例模式的程式碼如下:
def singleton(cls):
    instances = {}

    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


@singleton
class Foo(object):
    pass
4.3 使用__new__ __new__方法:  __new__()方法用於定義建立物件時執行的操作 object類中的__new__()方法完成物件建立過程中的記憶體空間申請,物件屬性初始化等一系列的操作。__new__是真正建立例項物件時用到的方法,所以重寫基類的__new__方法,以此來保證建立物件的時候只生成一個例項。 注意事項:     1.__new__()方法建立物件時自動執行。      2.覆蓋object類中的__new__方法後建立物件    將執行覆蓋後的方法。 注意事項:   __new__()方法僅僅是python開放出來給使用者干預建立物件時的一個操作入口,該方法並不是直接完成分配記憶體、建立物件的操作,建立物件的操作由python底層統一管理。 使用__new__方法實現單例模式的程式碼如下:
class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    pass

foo1 = MyClass()
foo2 = MyClass()
print(foo1)
print(foo2)
4.4 使用元類 元類是用於建立類物件的類,類物件建立例項物件時一定會呼叫__call__方法,因此在呼叫__call__時候保證始終只建立一個例項即可,type是python中的一個元類。 元類(metaclass)可以控制類的建立過程,它主要做三件事:   攔截類的建立   修改類的定義   返回修改後的類 使用元類實現單例模式的程式碼如下:
class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

# Python2
# class MyClass(object):
#     __metaclass__ = Singleton

# Python3
class MyClass(metaclass=Singleton):
    pass

foo1 = MyClass()
foo2 = MyClass()
print(foo1)
print(foo2)