在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python實現(xiàn)單例模式的五種寫法

馬哥Linux運(yùn)維 ? 來源:碼農(nóng)學(xué)習(xí)聯(lián)盟 ? 2023-05-24 11:27 ? 次閱讀

單例模式(Singleton Pattern)是一種常用的軟件設(shè)計模式,該模式的主要目的是確保某一個類只有一個實例存在。當(dāng)你希望在整個系統(tǒng)中,某個類只能出現(xiàn)一個實例時,單例對象就能派上用場。

比如,某個服務(wù)器程序的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息。如果在程序運(yùn)行期間,有很多地方都需要使用配置文件的內(nèi)容,也就是說,很多地方都需要創(chuàng)建 AppConfig 對象的實例,這就導(dǎo)致系統(tǒng)中存在多個 AppConfig 的實例對象,而這樣會嚴(yán)重浪費(fèi)內(nèi)存資源,尤其是在配置文件內(nèi)容很多的情況下。

事實上,類似 AppConfig 這樣的類,我們希望在程序運(yùn)行期間只存在一個實例對象。 在 Python 中,我們可以用多種方法來實現(xiàn)單例模式:

使用模塊

使用裝飾器

使用類

基于__new__方法實現(xiàn)

基于 metaclass 方式實現(xiàn)

下面來詳細(xì)介紹:

使用模塊 其實,Python 的模塊就是天然的單例模式,因為模塊在第一次導(dǎo)入時,會生成.pyc文件,當(dāng)?shù)诙螌?dǎo)入時,就會直接加載.pyc文件,而不會再次執(zhí)行模塊代碼。

因此,我們只需把相關(guān)的函數(shù)和數(shù)據(jù)定義在一個模塊中,就可以獲得一個單例對象了。

如果我們真的想要一個單例類,可以考慮這樣做:

classSingleton(object):
deffoo(self):
pass
singleton=Singleton()

將上面的代碼保存在文件 mysingleton.py 中,要使用時,直接在其他文件中導(dǎo)入此文件中的對象,這個對象即是單例模式的對象

frommysingletonimportsingleton

使用裝飾器

defSingleton(cls):
_instance={}

def_singleton(*args,**kargs):
ifclsnotin_instance:
_instance[cls]=cls(*args,**kargs)
return_instance[cls]

return_singleton


@Singleton
classA(object):
a=1

def__init__(self,x=0):
self.x=x


a1=A(2)
a2=A(3)

使用類

classSingleton(object):

def__init__(self):
pass

@classmethod
definstance(cls,*args,**kwargs):
ifnothasattr(Singleton,"_instance"):
Singleton._instance=Singleton(*args,**kwargs)
returnSingleton._instance

一般情況,大家以為這樣就完成了單例模式,但是當(dāng)使用多線程時會存在問題:

classSingleton(object):

def__init__(self):
pass

@classmethod
definstance(cls,*args,**kwargs):
ifnothasattr(Singleton,"_instance"):
Singleton._instance=Singleton(*args,**kwargs)
returnSingleton._instance

importthreading

deftask(arg):
obj=Singleton.instance()
print(obj)

foriinrange(10):
t=threading.Thread(target=task,args=[i,])
t.start()

程序執(zhí)行后,打印結(jié)果如下:

<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>
<__main__.Singleton?object?at?0x02C933D0>

看起來也沒有問題,那是因為執(zhí)行速度過快,如果在__init__方法中有一些 IO 操作,就會發(fā)現(xiàn)問題了。

下面我們通過time.sleep模擬,我們在上面__init__方法中加入以下代碼:

def__init__(self):
importtime
time.sleep(1)

重新執(zhí)行程序后,結(jié)果如下:

<__main__.Singleton?object?at?0x034A3410>
<__main__.Singleton?object?at?0x034BB990>
<__main__.Singleton?object?at?0x034BB910>
<__main__.Singleton?object?at?0x034ADED0>
<__main__.Singleton?object?at?0x034E6BD0>
<__main__.Singleton?object?at?0x034E6C10>
<__main__.Singleton?object?at?0x034E6B90>
<__main__.Singleton?object?at?0x034BBA30>
<__main__.Singleton?object?at?0x034F6B90>
<__main__.Singleton?object?at?0x034E6A90>

問題出現(xiàn)了!按照以上方式創(chuàng)建的單例,無法支持多線程。

解決辦法:加鎖!未加鎖部分并發(fā)執(zhí)行,加鎖部分串行執(zhí)行,速度降低,但是保證了數(shù)據(jù)安全。

importtime
importthreading


classSingleton(object):
_instance_lock=threading.Lock()

def__init__(self):
time.sleep(1)

@classmethod
definstance(cls,*args,**kwargs):
withSingleton._instance_lock:
ifnothasattr(Singleton,"_instance"):
Singleton._instance=Singleton(*args,**kwargs)
returnSingleton._instance


deftask(arg):
obj=Singleton.instance()
print(obj)


foriinrange(10):
t=threading.Thread(target=task,args=[i,])
t.start()


time.sleep(20)
obj=Singleton.instance()
print(obj)

打印結(jié)果如下:

<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>
<__main__.Singleton?object?at?0x02D6B110>

這樣就差不多了,但是還是有一點小問題,就是當(dāng)程序執(zhí)行時,執(zhí)行了time.sleep(20)后,下面實例化對象時,此時已經(jīng)是單例模式了。

但我們還是加了鎖,這樣不太好,再進(jìn)行一些優(yōu)化,把intance方法,改成下面這樣就行:

@classmethod
definstance(cls,*args,**kwargs):
ifnothasattr(Singleton,"_instance"):
withSingleton._instance_lock:
ifnothasattr(Singleton,"_instance"):
Singleton._instance=Singleton(*args,**kwargs)
returnSingleton._instance

這樣,一個可以支持多線程的單例模式就完成了。+

importtime
importthreading


classSingleton(object):
_instance_lock=threading.Lock()

def__init__(self):
time.sleep(1)

@classmethod
definstance(cls,*args,**kwargs):
ifnothasattr(Singleton,"_instance"):
withSingleton._instance_lock:
ifnothasattr(Singleton,"_instance"):
Singleton._instance=Singleton(*args,**kwargs)
returnSingleton._instance


deftask(arg):
obj=Singleton.instance()
print(obj)


foriinrange(10):
t=threading.Thread(target=task,args=[i,])
t.start()


time.sleep(20)
obj=Singleton.instance()
print(obj)

這種方式實現(xiàn)的單例模式,使用時會有限制,以后實例化必須通過obj = Singleton.instance()

如果用obj = Singleton(),這種方式得到的不是單例。

基于__new__方法實現(xiàn)

通過上面例子,我們可以知道,當(dāng)我們實現(xiàn)單例時,為了保證線程安全需要在內(nèi)部加入鎖。

我們知道,當(dāng)我們實例化一個對象時,是先執(zhí)行了類的__new__方法(我們沒寫時,默認(rèn)調(diào)用object.__new__),實例化對象;然后再執(zhí)行類的__init__方法,對這個對象進(jìn)行初始化,所有我們可以基于這個,實現(xiàn)單例模式。

importthreading


classSingleton(object):
_instance_lock=threading.Lock()

def__init__(self):
pass


def__new__(cls,*args,**kwargs):
ifnothasattr(Singleton,"_instance"):
withSingleton._instance_lock:
ifnothasattr(Singleton,"_instance"):
Singleton._instance=object.__new__(cls)
returnSingleton._instance

obj1=Singleton()
obj2=Singleton()
print(obj1,obj2)

deftask(arg):
obj=Singleton()
print(obj)

foriinrange(10):
t=threading.Thread(target=task,args=[i,])
t.start()

打印結(jié)果如下:

<__main__.Singleton?object?at?0x038B33D0><__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>
<__main__.Singleton?object?at?0x038B33D0>

采用這種方式的單例模式,以后實例化對象時,和平時實例化對象的方法一樣obj = Singleton()。

基于 metaclass 方式實現(xiàn)

相關(guān)知識:

類由 type 創(chuàng)建,創(chuàng)建類時,type 的__init__方法自動執(zhí)行,類() 執(zhí)行 type 的__call__方法(類的__new__方法,類的__init__方法)

對象由類創(chuàng)建,創(chuàng)建對象時,類的__init__方法自動執(zhí)行,對象()執(zhí)行類的__call__方法

例子:

classFoo:
def__init__(self):
pass

def__call__(self,*args,**kwargs):
pass

obj=Foo()
#執(zhí)行type的__call__方法,調(diào)用 Foo類(是type的對象)的__new__方法,用于創(chuàng)建對象,然后調(diào)用 Foo類(是type的對象)的__init__方法,用于對對象初始化。

obj()#執(zhí)行Foo的__call__方法

元類的使用:

classSingletonType(type):
def__init__(self,*args,**kwargs):
super(SingletonType,self).__init__(*args,**kwargs)

def__call__(cls,*args,**kwargs):#這里的cls,即Foo類
print('cls',cls)
obj=cls.__new__(cls,*args,**kwargs)
cls.__init__(obj,*args,**kwargs)#Foo.__init__(obj)
returnobj

classFoo(metaclass=SingletonType):#指定創(chuàng)建Foo的type為SingletonType
def__init__(self,name):
self.name=name
def__new__(cls,*args,**kwargs):
returnobject.__new__(cls)

obj=Foo('xx')

實現(xiàn)單例模式:

importthreading

classSingletonType(type):
_instance_lock=threading.Lock()
def__call__(cls,*args,**kwargs):
ifnothasattr(cls,"_instance"):
withSingletonType._instance_lock:
ifnothasattr(cls,"_instance"):
cls._instance=super(SingletonType,cls).__call__(*args,**kwargs)
returncls._instance

classFoo(metaclass=SingletonType):
def__init__(self,name):
self.name=name


obj1=Foo('name')
obj2=Foo('name')
print(obj1,obj2)

鏈接:https://www.cnblogs.com/huchong/p/8244279.html





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • python
    +關(guān)注

    關(guān)注

    56

    文章

    4799

    瀏覽量

    84810

原文標(biāo)題:Python實現(xiàn)單例模式的五種寫法!

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    談?wù)?b class='flag-5'>Python 中的迭代器模式

    中都得到了廣泛的應(yīng)用。 本文將談?wù)?Python 中的迭代器模式,主要內(nèi)容:什么是迭代器模式Python 如何實現(xiàn)迭代器
    發(fā)表于 11-23 13:10 ?802次閱讀
    談?wù)?b class='flag-5'>Python</b> 中的迭代器<b class='flag-5'>模式</b>

    verilog語言寫法實現(xiàn)問題!求解答~

    在看verilog代碼時,看到這樣兩表示方法:一是:“ wirea;assigna=b;”一是:“wirea=b;”請教各位大神這兩寫法
    發(fā)表于 01-29 14:33

    Python常用自增運(yùn)算寫法

    在學(xué)習(xí)任何一編程語言,運(yùn)算方法的學(xué)習(xí)是不可避免的,其中自增運(yùn)算符++的使用也是其中的重點,很多人容易弄不明白其用法,尤其是在Python中,其用法更加的不同!我們可以寫個實例來說明一下++運(yùn)算符在
    發(fā)表于 04-09 17:45

    怎么通過運(yùn)動檢測模式實現(xiàn)應(yīng)用產(chǎn)品的變革?

    通過審視運(yùn)動檢測模式——加速度(包括平移運(yùn)動,如位置和方向)、振動、沖擊、傾斜和旋轉(zhuǎn),各自的可能性,可以超越當(dāng)今大量MEMS應(yīng)用的范圍,極大地擴(kuò)大應(yīng)用選項。MEMS加速度計和陀螺儀如何通過
    發(fā)表于 07-30 07:47

    Python驅(qū)動程序實現(xiàn)輪電機(jī)的速度控制

    在有了別人的代碼后,我就很容易的參考他的方法來實現(xiàn)電機(jī)的這個功能,因此我簡單的寫了一個Python程序,通過調(diào)用之前寫的Python驅(qū)動程序,實現(xiàn)了對
    發(fā)表于 09-07 06:18

    PWM反饋控制模式研究

    PWM反饋控制模式研究
    發(fā)表于 08-08 10:46 ?20次下載
    <b class='flag-5'>五</b><b class='flag-5'>種</b>PWM反饋控制<b class='flag-5'>模式</b>研究

    模式詳解

    是private的話,會不更好的封裝該內(nèi)呢?我主要是應(yīng)用在使用普通類模擬枚舉類型里,后來發(fā)現(xiàn)這就是傳說中的模式。構(gòu)造函數(shù)弄成private 就是
    發(fā)表于 09-27 15:10 ?0次下載

    模式分成餓漢模式和懶漢模式解析

    定義:作為對象的創(chuàng)建模式模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。這個類稱為
    發(fā)表于 12-11 09:49 ?1651次閱讀

    Python下劃線的模式和命名約定

    本文介紹了Python下劃線和雙下劃線("dunder")的各種含義和命名約定,名稱修飾(name mangling)的工作原理,以及它如何影響你自己的Python類。
    的頭像 發(fā)表于 12-30 16:40 ?2026次閱讀
    <b class='flag-5'>Python</b><b class='flag-5'>五</b><b class='flag-5'>種</b>下劃線的<b class='flag-5'>模式</b>和命名約定

    Python略高級特征的使用方法

    Python 多好用不用多說,大家看看自己用的語言就知道了。但是 Python 隱藏的高級功能你都 get 了嗎?本文中,作者列舉了 Python
    的頭像 發(fā)表于 04-24 10:12 ?3222次閱讀

    開關(guān)電源PWM 反饋控制模式

    開關(guān)電源PWM 反饋控制模式(新型電源技術(shù)作業(yè)答案)-開關(guān)電源PWM 反饋控制模式
    發(fā)表于 09-27 10:01 ?76次下載
    開關(guān)電源PWM <b class='flag-5'>五</b><b class='flag-5'>種</b>反饋控制<b class='flag-5'>模式</b>

    詳解golang事務(wù)的三寫法

    本文中作者展示了 golang 事務(wù)的三寫法
    的頭像 發(fā)表于 03-16 08:52 ?5321次閱讀

    60個python日常高頻寫法

    今天給大家準(zhǔn)備了60個python日常高頻寫法,如果覺得有用,那就點贊收藏起來吧~
    的頭像 發(fā)表于 04-16 09:49 ?1043次閱讀

    模式(Singleton Pattern)實現(xiàn)的方法

    模式是指某個類只允許存在一個實例對象,例如在打印機(jī)打印文件時,一次只允許打印一個文件
    的頭像 發(fā)表于 06-01 11:44 ?647次閱讀
    <b class='flag-5'>單</b><b class='flag-5'>例</b><b class='flag-5'>模式</b>(Singleton Pattern)<b class='flag-5'>實現(xiàn)</b>的方法

    insert into 語句的三寫法

    INSERT INTO是MySQL中常用的一SQL語句,用于將數(shù)據(jù)插入到表中。此文將詳細(xì)介紹INSERT INTO語句的三不同寫法及其用途,并提供代碼示例和相關(guān)解釋。 正文: 一、基本插入
    的頭像 發(fā)表于 11-21 14:18 ?1.4w次閱讀
    主站蜘蛛池模板: 天天干天天摸| 久久国产中文字幕| 一区二区三区无码高清视频| 国产成人mv 在线播放| 国产成人在线影院| 欧美性猛交xxx嘿人猛交| 欧美在线激情| 日韩一卡2卡三卡4卡无卡网站| 久热99| 亚洲天堂成人网| 手机在线电影你懂的| 欧美一级高清片在线| 教官的好爽好深h片段| cijilu刺激 国产| 久久www免费人成高清| 国产亚洲综合精品一区二区三区| 国产黄色大片又色又爽| 黄色视屏日本| 超色视频| 深夜免费在线视频| 白嫩美女一级高清毛片免费看 | 日本人zzzwww| 久久综合九色综合精品| 最近免费| 国产精品福利午夜在线观看| 4455ee日本高清免费观看| 91麻豆麻豆| 日本写真高清视频免费网站网| 毛片韩国| 午夜影院免费体验| 亚洲第一在线播放| 国产va| 天天操天天干天天玩| 2022天天操| 激情丁香网| 中文字幕日韩三级| 日日操日日射| 成人a在线| 国产狂喷冒白浆免费视频| 乌克兰一级毛片| 色窝视频|