Python 中的單例模式
阿新 • • 發佈:2019-01-24
1.什麼是單例模式
單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個例項存在。當你希望在整個系統中,某個類只能出現一個例項時,單例物件就能派上用場。單例模式能控制一個類只能產生一個物件。
2.為什麼需要單例模式
3.單例模式應用場景
如果我們真的想要一個單例類,可以考慮這樣做:
,該函式會判斷某個類是否在字典 instances 中,如果不存在,則會將 cls 作為 key,cls(*args, **kw) 作為 value 存到 instances 中,否則,直接返回 instances[cls]。
使用裝飾器實現單例模式的程式碼如下:
- 當每個例項都會佔用資源,而且例項初始化會影響效能,這個時候就可以考慮使用單例模式,它給我們帶來的好處是隻有一個例項佔用資源,並且只需初始化一次;
- 當有同步需要的時候,可以通過一個例項來進行同步控制,比如對某個共享檔案(如日誌檔案)的控制,對計數器的同步控制等,這種情況下由於只有一個例項,所以不用擔心同步問題。
- Python的logger就是一個單例模式,用以日誌記錄
- Windows的資源管理器是一個單例模式
- 執行緒池,資料庫連線池等資源池一般也用單例模式
- 網站計數器
- 使用模組
- 使用 __new__
- 使用裝飾器(decorator)
- 使用元類
# 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,它返回了一個內部函式 wrapperdef 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)