單例模式
單例模式(Singleton Pattern)是一種常用的軟件設計模式把夸,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統(tǒng)中筐赔,某個類只能出現(xiàn)一個實例時萧落,單例對象就能派上用場珊随。
比如,某個服務器程序的配置信息存放在一個文件中污淋,客戶端通過一個 AppConfig 的類來讀取配置文件的信息顶滩。如果在程序運行期間,有很多地方都需要使用配置文件的內(nèi)容寸爆,也就是說礁鲁,很多地方都需要創(chuàng)建 AppConfig 對象的實例,這就導致系統(tǒng)中存在多個 AppConfig 的實例對象赁豆,而這樣會嚴重浪費內(nèi)存資源仅醇,尤其是在配置文件內(nèi)容很多的情況下。事實上魔种,類似 AppConfig 這樣的類析二,我們希望在程序運行期間只存在一個實例對象。
在 Python 中,我們可以用多種方法來實現(xiàn)單例模式:
使用模塊
使用__new__
使用裝飾器(decorator)
使用元類(metaclass)
使用模塊
其實叶摄,Python 的模塊就是天然的單例模式属韧,因為模塊在第一次導入時,會生成.pyc文件蛤吓,當?shù)诙螌霑r宵喂,就會直接加載.pyc文件,而不會再次執(zhí)行模塊代碼会傲。因此樊破,我們只需把相關的函數(shù)和數(shù)據(jù)定義在一個模塊中,就可以獲得一個單例對象了唆铐。如果我們真的想要一個單例類哲戚,可以考慮這樣做
# mysingleton.py
class My_Singleton(object):
???????? def foo(self):
??????????????? pass
my_singleton = My_Singleton()
將上面的代碼保存在文件mysingleton.py中,然后這樣使用
from mysingleton import my_singleton
my_singleton.foo()
使用__new__
為了使類只能出現(xiàn)一個實例艾岂,我們可以使用__new__來控制實例的創(chuàng)建過程顺少,代碼如下:
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):
a = 1
在上面的代碼中,我們將類的實例和一個類變量_instance關聯(lián)起來王浴,如果cls._instance為 None 則創(chuàng)建實例脆炎,否則直接返回cls._instance。
執(zhí)行情況如下:
>>> one = MyClass()
>>> two = MyClass()
>>> one == two
True
>>> one is two
True
>>> id(one), id(two)
(4303862608, 4303862608)
使用裝飾器
我們知道氓辣,裝飾器(decorator)可以動態(tài)地修改一個類或函數(shù)的功能秒裕。這里,我們也可以使用裝飾器來裝飾某個類钞啸,使其只能生成一個實例几蜻,代碼如下:
from functools import wraps
??????? def singleton(cls):
????????????????? instances = {}
????? @wraps(cls)
?????? def getinstance(*args, **kw):
?????????????????? if cls not in instances:
??????????????????????????? instances[cls] = cls(*args, **kw)
????????????????? ? ? ? ? ? return instances[cls]
??????????????? return getinstance
@singleton
class MyClass(object):
a = 1
在上面,我們定義了一個裝飾器singleton体斩,它返回了一個內(nèi)部函數(shù)getinstance梭稚,該函數(shù)會判斷某個類是否在字典instances中,如果不存在絮吵,則會將cls作為 key弧烤,cls(*args, **kw)作為 value 存到instances中,否則蹬敲,直接返回instances[cls]暇昂。
使用 metaclass
元類(metaclass)可以控制類的創(chuàng)建過程,它主要做三件事:
攔截類的創(chuàng)建
修改類的定義
返回修改后的類
使用元類實現(xiàn)單例模式的代碼如下:
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
小結
Python 的模塊是天然的單例模式伴嗡,這在大部分情況下應該是夠用的急波,當然,我們也可以使用裝飾器闹究、元類等方法
參考資料
Creating a singleton in Python - Stack Overflow
design patterns - Python’s use ofnewandinit? - Stack Overflow