有些時(shí)候你的項(xiàng)目中難免需要一些全局唯一的對(duì)象,這些對(duì)象大多是一些工具性的東西,在Python中實(shí)現(xiàn)單例模式并不是什么難事。以下總結(jié)幾種方法:
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了阿勒泰免費(fèi)建站歡迎大家使用!
使用類裝飾器
使用裝飾器實(shí)現(xiàn)單例類的時(shí)候,類本身并不知道自己是單例的,所以寫代碼的人可以不care這個(gè),只要正常寫自己的類的實(shí)現(xiàn)就可以,類的單例有裝飾器保證。
def singleton(cls):
instances = {}
def _wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return _wrapper
你會(huì)發(fā)現(xiàn)singleton裝飾器內(nèi)部使用了一個(gè)dict。當(dāng)然你也可以用其他的方式,不過以下的實(shí)現(xiàn)是錯(cuò)誤的:
def singleton(cls):
_instance = None #外部作用域的引用對(duì)于嵌套的內(nèi)部作用域是只讀的
def _wrapper(*args, **kwargs):
if _instance is None: #解釋器會(huì)拋出"UnboundLocalError: ...referenced before assignment"
_instance = cls(*args, **kwargs) #賦值行為使解釋器將"_instance"看作局部變量
return _instance
return _wrapper
使用元類(__metaclass__)和可調(diào)用對(duì)象(__call__)
Python的對(duì)象系統(tǒng)中一些皆對(duì)象,類也不例外,可以稱之為”類型對(duì)象”,比較繞,但仔細(xì)思考也不難:類本身也是一種對(duì)象,只不過這種對(duì)象很特殊,它表示某一種類型。是對(duì)象,那必然是實(shí)例化來的,那么誰實(shí)例化后是這種類型對(duì)象呢?也就是元類。
Python中,class關(guān)鍵字表示定義一個(gè)類對(duì)象,此時(shí)解釋器會(huì)按一定規(guī)則尋找__metaclass__,如果找到了,就調(diào)用對(duì)應(yīng)的元類實(shí)現(xiàn)來實(shí)例化該類對(duì)象;沒找到,就會(huì)調(diào)用type元類來實(shí)例化該類對(duì)象。
__call__是Python的魔術(shù)方法,Python的面向?qū)ο笫恰盌uck type”的,意味著對(duì)象的行為可以通過實(shí)現(xiàn)協(xié)議來實(shí)現(xiàn),可以看作是一種特殊的接口形式。某個(gè)類實(shí)現(xiàn)了__call__方法意味著該類的對(duì)象是可調(diào)用的,可以想像函數(shù)調(diào)用的樣子。再考慮一下foo=Foo()這種實(shí)例化的形式,是不是很像啊。結(jié)合元類的概念,可以看出,Foo類是單例的,則在調(diào)用Foo()的時(shí)候每次都返回了同樣的對(duì)象。而Foo作為一個(gè)類對(duì)象是單例的,意味著它的類(即生成它的元類)是實(shí)現(xiàn)了__call__方法的。所以可以如下實(shí)現(xiàn):
class Singleton(type):
def __init__(cls, name, bases, attrs):
super(Singleton, cls).__init__(name, bases, attrs)
cls._instance = None
def __call__(cls, *args, **kwargs):
if cls._instance is None
# 以下不要使用'cls._instance = cls(*args, **kwargs)', 防止死循環(huán),
# cls的調(diào)用行為已經(jīng)被當(dāng)前'__call__'協(xié)議攔截了
# 使用super(Singleton, cls).__call__來生成cls的實(shí)例
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
class Foo(object): #單例類
__metaclass__ = Singleton
a = Foo()
b = Foo()
a is b
True
a.x = 1
b.x
1
使用__new__
__init__不是Python對(duì)象的構(gòu)造方法,__init__只負(fù)責(zé)初始化實(shí)例對(duì)象,在調(diào)用__init__方法之前,會(huì)首先調(diào)用__new__方法生成對(duì)象,可以認(rèn)為__new__方法充當(dāng)了構(gòu)造方法的角色。所以可以在__new__中加以控制,使得某個(gè)類只生成唯一對(duì)象。具體實(shí)現(xiàn)時(shí)可以實(shí)現(xiàn)一個(gè)父類,重載__new__方法,單例類只需要繼承這個(gè)父類就好。
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
class Foo(Singleton): #單例類
a = 1
在聊這之前我們首先要明確的是,單例模式在實(shí)際中的意義以及在python中具有實(shí)現(xiàn)的價(jià)值?
當(dāng)前,相信有很多人支持單例模式,也有不少人反對(duì),尤其是在python中,目前依舊具有很大的爭(zhēng)議性。我們要在評(píng)論之前首先要了解單例模式
什么是單例模式?
顧名思義:就是單個(gè)模式
單例模式是一種常見的軟件設(shè)置模式,在它的核心結(jié)構(gòu)中只包含一個(gè)被稱為單例類的特殊類,通過單例模式可以保證系統(tǒng)中的一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問,從而方便對(duì)實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源。如果希望在系統(tǒng)中某個(gè)對(duì)象只能存在一個(gè),單例模式是最好的解決方案。
單例模式的要點(diǎn)有三類
某個(gè)類只能有一個(gè)實(shí)例
它必須創(chuàng)建這個(gè)實(shí)例
它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例
但是從具體角度實(shí)現(xiàn)來說的話,又可以分為三點(diǎn)
單例模式的類只能提供私有的構(gòu)造函數(shù)
類定義中含有一個(gè)該類的靜態(tài)私有對(duì)象
該類提供了一個(gè)靜態(tài)的共有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對(duì)象
一、實(shí)例控制
單例模式會(huì)阻止其他對(duì)象實(shí)例化其自己的單例對(duì)象的副本,從而確保所有對(duì)象都訪問唯一實(shí)例。
二、靈活性
因?yàn)轭惪刂屏藢?shí)例化過程,所以類可以靈活更改實(shí)例化過程。
缺點(diǎn):
一、開銷
雖然數(shù)量很少,但如果每次對(duì)象請(qǐng)求引用時(shí)都要檢查是否存在類的實(shí)例,將仍然需要一些開銷??梢酝ㄟ^使用靜態(tài)初始化解決此問題。
二、可能的開發(fā)混淆
使用單例對(duì)象(尤其在類庫中定義的對(duì)象)時(shí),開發(fā)人員必須記住自己不能使用?new關(guān)鍵字實(shí)例化對(duì)象。因?yàn)榭赡軣o法訪問庫源代碼,因此應(yīng)用程序開發(fā)人員可能會(huì)意外發(fā)現(xiàn)自己無法直接實(shí)例化此類。
三、對(duì)象生存期
不能解決刪除單個(gè)對(duì)象的問題。在提供內(nèi)存管理的語言中(例如基于.NET Framework的語言),只有單例類能夠?qū)е聦?shí)例被取消分配,因?yàn)樗瑢?duì)該實(shí)例的私有引用。在某些語言中(如 C++),其他類可以刪除對(duì)象實(shí)例,但這樣會(huì)導(dǎo)致單例類中出現(xiàn)懸浮引用。
常用幾種方式
通過面向的特性,簡(jiǎn)單的構(gòu)造出單例模式
123456789101112131415? ?# ########### 單例類定義 ###########class?Foo(object):??????__instance?=?None??????@staticmethod????def?singleton():????????if?Foo.__instance:????????????return?Foo.__instance????????else:????????????Foo.__instance?=?Foo()????????????return?Foo.__instance??# ########### 獲取實(shí)例 ###########obj?=?Foo.singleton()? ?
當(dāng)用于WEB界面時(shí),單例模式的簡(jiǎn)單運(yùn)用
web 單例模式
不過我們需要注意的是:
特殊方法__new__是一個(gè)元構(gòu)造程序,每當(dāng)一個(gè)對(duì)象必須被factory類實(shí)例化時(shí),就將調(diào)用它。__new__方法必須返回一個(gè)類的實(shí)例,因此它可以在對(duì)象創(chuàng)建之前或之后修改類。
因?yàn)開_init__在子類中不會(huì)被隱式調(diào)用,所以__new__可以用來確定已經(jīng)在整個(gè)類層次完成了初始化構(gòu)造。__new__是對(duì)于對(duì)象狀態(tài)隱式初始化需求的回應(yīng),使得可以在比__init__更低的一個(gè)層次上定義一個(gè)初始化,這個(gè)初始化總是會(huì)被調(diào)用。
與__init__()相比__new__()方法更像一個(gè)真正的構(gòu)造器。隨著類和類型的統(tǒng)一,用戶可以對(duì)內(nèi)建類型進(jìn)行派生,因此需要一種途徑來實(shí)例化不可變對(duì)象,比如派生字符串,在這種情況下解釋器則調(diào)用類的__new__()方法,一個(gè)靜態(tài)方法,并且傳入的參數(shù)是在類實(shí)例化操作時(shí)生成的。__new__()會(huì)調(diào)用父類的__new__()來創(chuàng)建對(duì)象(向上代理)
·__new__必須返回一個(gè)合法的實(shí)例,這樣解釋器在調(diào)用__init__()時(shí),就可以吧這個(gè)實(shí)例作為self傳給他。調(diào)用父類的__new__()來創(chuàng)建對(duì)象,正向其他語言使用new關(guān)鍵字一樣
總結(jié)
單利模式存在的目的是保證當(dāng)前內(nèi)存中僅存在單個(gè)實(shí)例,避免內(nèi)存浪費(fèi)?。。?/p>
一。單例模式
一般情況下,類可以生成任意個(gè)實(shí)例,而單例模式只生成一個(gè)實(shí)例
我們先用單例模式設(shè)計(jì)一個(gè)Rectangle類
然后用__new__方法設(shè)計(jì)單例模式,代碼如下
然后我們來驗(yàn)證下,單例模式下是否只能生成一個(gè)實(shí)例
單例模式在程序設(shè)計(jì)中比較典型的應(yīng)用場(chǎng)景:多個(gè)用戶同時(shí)調(diào)用某個(gè)模塊時(shí),會(huì)生成一些日志,我們希望這些日志存在同一個(gè)文件內(nèi),而不是多個(gè)文件。
在生成日志模塊我們就可以采用單例模式進(jìn)行設(shè)計(jì)。
二。反射
概念:簡(jiǎn)單來說就是可以利用字符串來映射模塊中的相應(yīng)方法然后可以操作模塊中相應(yīng)的方法
我們以一個(gè)飯店點(diǎn)菜的實(shí)際場(chǎng)景來理解Python的反射機(jī)制
hasatter(對(duì)象,屬性或方法名)
判斷對(duì)象中是否有某個(gè)屬性或某個(gè)方法,返回值是布爾型
getattr(對(duì)象,屬性或方法名,缺省值) 判斷對(duì)象中是否有某個(gè)屬性或某個(gè)方法,如果有返回方法本身,沒有則返回缺省值
setattr(對(duì)象,屬性,新值)
將實(shí)例的屬性改為新的值,如果屬性不存在則新建
我們給實(shí)例guke1加個(gè)價(jià)格屬性
當(dāng)前標(biāo)題:單例函數(shù)python 單例代碼實(shí)現(xiàn)
轉(zhuǎn)載源于:http://jinyejixie.com/article26/dosjojg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司、企業(yè)網(wǎng)站制作、面包屑導(dǎo)航、品牌網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)