[TOC]
單例模式
單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式贞间,該模式的主要目的是確保某一個類只有一個實(shí)例存在挠唆。當(dāng)你希望在整個系統(tǒng)中处窥,某個類只能出現(xiàn)一個實(shí)例時,單例對象就能派上用場玄组。
比如滔驾,某個服務(wù)器程序的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息俄讹。如果在程序運(yùn)行期間哆致,有很多地方都需要使用配置文件的內(nèi)容,也就是說患膛,很多地方都需要創(chuàng)建 AppConfig 對象的實(shí)例摊阀,這就導(dǎo)致系統(tǒng)中存在多個 AppConfig 的實(shí)例對象,而這樣會嚴(yán)重浪費(fèi)內(nèi)存資源,尤其是在配置文件內(nèi)容很多的情況下驹溃。事實(shí)上城丧,類似 AppConfig 這樣的類,我們希望在程序運(yùn)行期間只存在一個實(shí)例對象豌鹤。
在 Python 中亡哄,我們可以用多種方法來實(shí)現(xiàn)單例模式:
- 使用模塊
- 使用
__new__
- 使用裝飾器(decorator)
- 使用元類(metaclass)
使用模塊
其實(shí),Python 的模塊就是天然的單例模式布疙,因?yàn)槟K在第一次導(dǎo)入時蚊惯,會生成 .pyc 文件,當(dāng)?shù)诙螌?dǎo)入時灵临,就會直接加載 .pyc 文件截型,而不會再次執(zhí)行模塊代碼。因此儒溉,我們只需把相關(guān)的函數(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()
裝飾器
def Singleton(cls):
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
@Singleton
class A(object):
a = 1
def __init__(self, x=0):
self.x = x
a1 = A(2)
a2 = A(3)
基于__new__
方法
#單例模式 在多線程下失效
class Singleton:
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
cls._instance = object.__new__(cls, *args, **kw)
return cls._instance
基于__new__
方法加線程鎖
# 基于__new__然后加鎖
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
基于metaclass
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
# print(args)
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
# def __new__(cls, *args, **kwargs):
# print('Foo __init__')
# return object.__new__(cls)
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)