2018-03-24

[TOC]

參考:

http://www.cnblogs.com/yuanchenqi/articles/8323452.html#_label1

https://www.cnblogs.com/huchong/p/8244279.html#_lab2_1_2

  • 使用文件(模塊導(dǎo)入)

  • 使用 new(類的方式)

  • 使用元類(metaclass)

  • 使用裝飾器(decorator)

在哪里用得到單例:

  • 數(shù)據(jù)庫連接池

單例模式:

文件導(dǎo)入方式實(shí)現(xiàn)

利用文件導(dǎo)入懂鸵,那么被導(dǎo)入文件只加載一次的特性,實(shí)現(xiàn)單例模式。


#s1.py

print('s111111111111111111')

#s2.py

print('s22222222222222222222222')

#run.py

import s1

import s2

import s1

import s2

image.png

實(shí)現(xiàn)多次導(dǎo)入


import s1

import s2

import s1

import s2

# 如果要想實(shí)現(xiàn)導(dǎo)入多次加載

import importlib

importlib.reload(s1)

importlib.reload(s2)

導(dǎo)入類的實(shí)例,被導(dǎo)入的文件中的類只實(shí)例化一次,而不會(huì)因?yàn)樵谄渌募虮疚募?nèi)多次導(dǎo)入而生成多個(gè)實(shí)例。在連接數(shù)據(jù)庫時(shí),這個(gè)很重要

db.py


class Foo(object):

def __init__(self):

self.conn = "連接數(shù)據(jù)庫"

def get(self):

print(self.conn)

obj = Foo()

# import redis

# obj = redis.Redis(host="10.0.0.61",

# port=6379

# )

view.py


import t_db

print(t_db.obj)

run.py


import t_db

import t_view

print(t_db.obj)

[圖片上傳失敗...(image-e27196-1521871654703)]

類方式

普通實(shí)現(xiàn)


# 1\. 初步實(shí)現(xiàn)

# class Foo(object):

#

# instance = None #靜態(tài)變量跪削,實(shí)例共享

#

# def __init__(self):

# # 因?yàn)槭菃卫瑳]有傳參的必要迂求,因?yàn)槎家缘谝粋€(gè)為準(zhǔn)

# self.a = 1

# self.b = 2

#

# @classmethod

# def get_instance(cls,*args,**kwargs):

# if not getattr(Foo,'instance'): #這個(gè)類中是否有instance碾盐,沒有則創(chuàng)建后返回,有則直接返回

# obj = cls(*args,**kwargs)

# cls.instance = obj

# return cls.instance

#

# obj1 = print(Foo.get_instance())

# obj2 = print(Foo.get_instance())

#

# # 返回

# # <__main__.Foo object at 0x00000000011AAF28>

# # <__main__.Foo object at 0x00000000011AAF28>

# 缺點(diǎn):

# 1.可以實(shí)現(xiàn)單位揩局,但線程不安全

# 2.改變了實(shí)例化的形式(不是Foo())

# 2 最終實(shí)現(xiàn)

import threading

class Foo(object):

lock = threading.Lock() # 實(shí)例化一個(gè)鎖

instance = None #靜態(tài)變量毫玖,實(shí)例共享

def __init__(self):

# 因?yàn)槭菃卫瑳]有傳參的必要凌盯,因?yàn)槎家缘谝粋€(gè)為準(zhǔn)

self.a = 1

self.b = 2

import time

time.sleep(2)

@classmethod

def get_instance(cls,*args,**kwargs):

if not getattr(Foo, 'instance'):

# 每一次線程實(shí)例化時(shí)付枫,都要上鎖再釋放,試想如果實(shí)例化時(shí)不是seleep不是2秒驰怎,而是10秒或更多阐滩,線程進(jìn)來創(chuàng)建實(shí)例,第二次程序中已以有一instance砸西,其實(shí)沒有必要上鎖了叶眉,但還是會(huì)進(jìn)行加鎖處理址儒,所以判斷一下

with cls.lock: # 相當(dāng)于上鎖芹枷,使用完自己relese

if not getattr(Foo,'instance'): #這個(gè)類中是否有instance,沒有則創(chuàng)建后返回莲趣,有則直接返回

obj = cls(*args,**kwargs)

cls.instance = obj

return cls.instance

return cls.instance

# 使用多線程執(zhí)行實(shí)例動(dòng)作鸳慈,看是否有還是單例

def task():

obj = Foo.get_instance()

print(obj)

import threading

for i in range(5):

t = threading.Thread(target=task,)

t.start()

1. 當(dāng)使用多線程進(jìn)行實(shí)例化時(shí),init里如果不加sleep喧伞,那么程序執(zhí)行太快走芋,第二個(gè)線程進(jìn)入程序已經(jīng)有值,所以顯示實(shí)例id還是一樣的

但init里如果加sleep潘鲫,那么第二次進(jìn)入程序翁逞,類中沒有instance,所以會(huì)再創(chuàng)建返回溉仑,這樣的話 就不是單例了挖函,這就是所謂的線程安全

2. 為了解決線程安全,可以使用加鎖解決,但是使程序變成了串行浊竟,并且每一次線程實(shí)例化時(shí)怨喘,都要上鎖再釋放津畸,試想如果實(shí)例化時(shí)不是seleep不是2秒,而是10秒或更多必怜,第一個(gè)線程進(jìn)來創(chuàng)建實(shí)例肉拓,第二個(gè)線程再進(jìn)入程序中已以有一instance,其實(shí)沒有必要上鎖了梳庆,但還是會(huì)進(jìn)行加鎖處理暖途,所以判斷一下

new方法實(shí)現(xiàn)

使用new方法實(shí)現(xiàn)的好處是不會(huì)改變類實(shí)例化的方式還是obj = Foo()


# 使用__new__ 實(shí)現(xiàn)

import threading

import time

class Foo(object):

instance = None

lock = threading.Lock()

def __init__(self):

self.a1 = 1

self.a2 = 2

time.sleep(2)

@classmethod #一定要是類方法

def __new__(cls, *args,**kwargs):

if not cls.instance:

with cls.lock:

if not cls.instance:

obj = super(Foo,cls).__new__(*args, **kwargs) # obj = Foo() 即實(shí)例化Foo

cls.instance = obj

return cls.instance

return cls.instance

def task():

obj = Foo()

print(obj)

import threading

for i in range(5):

t = threading.Thread(target=task,)

t.start()

metaclass形式實(shí)現(xiàn)

metaclass方式的實(shí)現(xiàn)原理

[圖片上傳失敗...(image-1b1b5e-1521871654703)]


import threading

lock = threading.Lock()

class Singleton(type):

# print(123) # 在class創(chuàng)建Foo類時(shí)就會(huì)執(zhí)行Mytype

def __call__(self, *args, **kwargs):

if not hasattr(self,'instance'):

with lock:

# print(self) #<class '__main__.Foo'> ,self 就是Foo

if not hasattr(self,'instance'):

obj = self.__new__(self, *args, **kwargs) # new實(shí)例化一個(gè)對(duì)象,即如果沒instance膏执,那么創(chuàng)建一個(gè)

obj.__init__( *args, **kwargs) # 對(duì)象.init 即構(gòu)造這個(gè)實(shí)例

setattr(self,'instance',obj) # 在這個(gè)實(shí)例中設(shè)置一個(gè)靜態(tài)變量instance

return getattr(self,'instance')

return getattr(self, 'instance')

class Foo(object,metaclass=Singleton):

def __init__(self):

self.name = 'xxx'

def task():

obj = Foo()

print(obj)

import threading

for i in range(5):

t = threading.Thread(target=task,)

t.start()

[圖片上傳失敗...(image-2bdda4-1521871654702)]

1. obj1 = Foo() 實(shí)例化類

2. Foo(),加了括號(hào)丧肴,執(zhí)行父類的__call__ 方法

3. 在這個(gè)方法中判斷如果沒有instance

4. 那么創(chuàng)建這個(gè)實(shí)例

5. 使用實(shí)例的init方法構(gòu)造這個(gè)實(shí)例

7. 把實(shí)例賦值給這個(gè)實(shí)例的instance

8. return

9. obj2 = Foo 第二個(gè)實(shí)例化類

10. 如果有instance,已以有了

11. 直接返回

使用metaclass形式的好處是胧后,Mytype類不用變芋浮,如果給讓哪個(gè)類變成單例,那么使他metaclass=Mytype就好了壳快。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纸巷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子眶痰,更是在濱河造成了極大的恐慌瘤旨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竖伯,死亡現(xiàn)場(chǎng)離奇詭異存哲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)七婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門祟偷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人打厘,你說我怎么就攤上這事修肠。” “怎么了户盯?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵嵌施,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我莽鸭,道長(zhǎng)吗伤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任硫眨,我火速辦了婚禮足淆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己缸浦,他們只是感情好夕冲,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裂逐,像睡著了一般歹鱼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卜高,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天弥姻,我揣著相機(jī)與錄音,去河邊找鬼掺涛。 笑死庭敦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的薪缆。 我是一名探鬼主播秧廉,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拣帽!你這毒婦竟也來了疼电?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤减拭,失蹤者是張志新(化名)和其女友劉穎蔽豺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拧粪,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡修陡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了可霎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魄鸦。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖啥纸,靈堂內(nèi)的尸體忽然破棺而出号杏,到底是詐尸還是另有隱情婴氮,我是刑警寧澤斯棒,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站主经,受9級(jí)特大地震影響荣暮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜罩驻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一穗酥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦砾跃、人聲如沸骏啰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽判耕。三九已至,卻和暖如春翘骂,著一層夾襖步出監(jiān)牢的瞬間壁熄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工碳竟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留草丧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓莹桅,卻偏偏與公主長(zhǎng)得像昌执,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诈泼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容