2.1.4 Python單例模式

花姐毛毛腿發表於2019-01-21

點選跳轉Python筆記總目錄

本節目錄

一、內容

二、角色

三、使用場景

四、優點

五、單例模式的四種實現方式

六、單例模式的應用(會在資料庫連線池中用到單例模式)

七、額外補充的一種用裝飾器實現的單利模式


一、內容

保證一個類只有一個例項,並提供一個訪問它的全域性訪問點

二、角色

單例,即只有一個類的例項

三、使用場景

當類只有一個例項而且客戶可以從一個眾所周知的訪問點訪問它時比如:資料庫連結、Socket建立連結

四、優點

  • 對唯一例項的受控訪問
  • 對唯一例項的受控訪問

單利相當於全域性變數,但防止了名稱空間被汙染與單利模式功能相似的概念:全域性變數、靜態變數(方法)

試問?為什麼用單例模式,不用全域性變數呢?

  答、全域性變數可能會有名稱空間的干擾,如果有重名的可能會被覆蓋

五、單例模式的四種實現方式

1、檔案匯入的形式(常用)

s1.pyclass Foo(object):    def test(self):        print("123")v = Foo()#v是Foo的例項s2.pyfrom s1 import v as v1print(v1,id(v1))  #<
s1.Foo object at 0x0000000002221710>
35788560
from s1 import v as v2print(v1,id(v2)) #<
s1.Foo object at 0x0000000002221710>
35788560
## 兩個的記憶體地址是一樣的## 檔案載入的時候,第一次匯入後,再次匯入時不會再重新載入。複製程式碼

2、基於類實現的單例模式

## **********************單例模式:無法支援多執行緒情況**************=class Singleton(object):    def __init__(self):        import time        time.sleep(1)    @classmethod    def instance(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instanceimport threadingdef task(arg):    obj = Singleton.instance()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()## ********************單例模式:支援多執行緒情況****************、import timeimport threadingclass Singleton(object):    _instance_lock = threading.Lock()    def __init__(self):        time.sleep(1)    @classmethod    def instance(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            with Singleton._instance_lock:   #為了保證執行緒安全在內部加鎖                if not hasattr(Singleton, "_instance"):                    Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instancedef task(arg):    obj = Singleton.instance()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()time.sleep(20)obj = Singleton.instance()print(obj)## 使用先說明,以後用單例模式,obj = Singleton.instance()## 示例:## obj1 = Singleton.instance()## obj2 = Singleton.instance()## print(obj1,obj2)## 錯誤示例## obj1 = Singleton()## obj2 = Singleton()## print(obj1,obj2)複製程式碼

3、基於__new__實現的單例模式(最常用)

class Singleton:    def __new__(cls, *args, **kw):        if not hasattr(cls, '_instance'):            cls._instance = object.__new__(cls, *args, **kw)        return cls._instanceone = Singleton()two = Singleton()two.a = 3print(one.a)## 3## one和two完全相同,可以用id(), **, is檢測print(id(one))## 29097904print(id(two))## 29097904print(one ** two)## Trueprint(one is two)複製程式碼

4、基於metaclass(元類)實現的單例模式

"""1.物件是類建立,建立物件時候類的__init__方法自動執行,物件()執行類的 __call__ 方法2.類是type建立,建立類時候type的__init__方法自動執行,類() 執行type的 __call__方法(類的__new__方法,類的__init__方法)## 第0步: 執行type的 __init__ 方法【類是type的物件】class Foo:    def __init__(self):        pass    def __call__(self, *args, **kwargs):        pass## 第1步: 執行type的 __call__ 方法##        1.1  呼叫 Foo類(是type的物件)的 __new__方法,用於建立物件。##        1.2  呼叫 Foo類(是type的物件)的 __init__方法,用於對物件初始化。obj = Foo()## 第2步:執行Foo的 __call__ 方法obj()"""## **********=類的執行流程****************class SingletonType(type):    def __init__(self,*args,**kwargs):        print(self)  #會不會列印?  #<
class '__main__.Foo'>
super(SingletonType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): #cls = Foo obj = cls.__new__(cls, *args, **kwargs) obj.__init__(*args, **kwargs) return objclass Foo(metaclass=SingletonType): def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs)''' 1、物件是類建立的,建立物件時類的__init__方法會自動執行,物件()執行類的__call__方法 2、類是type建立的,建立類時候type類的__init__方法會自動執行,類()會先執行type的__call__方法(呼叫類的__new__,__init__方法) Foo 這個類是由SingletonType這個類建立的'''obj = Foo("hiayan")## ************第三種方式實現單例模式****************=import threadingclass SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instanceclass Foo(metaclass=SingletonType): def __init__(self,name): self.name = nameobj1 = Foo('name')obj2 = Foo('name')print(obj1,obj2)複製程式碼

六、單例模式的應用(會在資料庫連線池中用到單例模式)

pool.py

import pymysqlimport threadingfrom DBUtils.PooledDB import PooledDBclass SingletonDBPool(object):    _instance_lock = threading.Lock()    def __init__(self):        self.pool = PooledDB(            creator=pymysql,  ## 使用連結資料庫的模組            maxconnections=6,  ## 連線池允許的最大連線數,0和None表示不限制連線數            mincached=2,  ## 初始化時,連結池中至少建立的空閒的連結,0表示不建立            maxcached=5,  ## 連結池中最多閒置的連結,0和None不限制            maxshared=3,            ## 連結池中最多共享的連結數量,0和None表示全部共享。PS: 無用,因為pymysql和MySQLdb等模組的 threadsafety都為1,所有值無論設定為多少,_maxcached永遠為0,所以永遠是所有連結都共享。            blocking=True,  ## 連線池中如果沒有可用連線後,是否阻塞等待。True,等待;False,不等待然後報錯            maxusage=None,  ## 一個連結最多被重複使用的次數,None表示無限制            setsession=[],  ## 開始會話前執行的命令列表。如:["set datestyle to ...", "set time zone ..."]            ping=0,            ## ping MySQL服務端,檢查是否服務可用。## 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always            host='127.0.0.1',            port=3306,            user='root',            password='123',            database='pooldb',            charset='utf8'        )    def __new__(cls, *args, **kwargs):        if not hasattr(SingletonDBPool, "_instance"):            with SingletonDBPool._instance_lock:                if not hasattr(SingletonDBPool, "_instance"):                    SingletonDBPool._instance = object.__new__(cls, *args, **kwargs)        return SingletonDBPool._instance    def connect(self):        return self.pool.connection()複製程式碼

app.py

from pool import SingletonDBPooldef run():    pool = SingletonDBPool()    conn = pool.connect()    ## xxxxxx    cursor = conn.cursor()    cursor.execute("select * from td where id=%s", [5, ])    result = cursor.fetchall()  ## 獲取資料    cursor.close()    conn.close()if __name__ ** '__main__':    run()複製程式碼

七、額外補充的一種用裝飾器實現的單例模式

#def wrapper(cls):    instance = {
} def inner(*args,**kwargs): if cls not in instance: instance[cls] = cls(*args,**kwargs) return instance[cls] return inner@wrapperclass Singleton(object): def __init__(self,name,age): self.name = name self.age = ageobj1 = Singleton('haiyan',22)obj2 = Singleton('xx',22)print(obj1)print(obj2)複製程式碼

來源:https://juejin.im/post/5c45897ae51d4552475ff1de

相關文章