單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個實體存在,當你希望在整個系統中,某個類只能出現一個實體時,單例物件就能派上用場,
比如,某個服務器程式的配置資訊存放在一個檔案中,客戶端通過一個 AppConfig 的類來讀取組態檔的資訊,如果在程式運行期間,有很多地方都需要使用組態檔的內容,也就是說,很多地方都需要創建 AppConfig 物件的實體,這就導致系統中存在多個 AppConfig 的實體物件,而這樣會嚴重浪費記憶體資源,尤其是在組態檔內容很多的情況下,事實上,類似 AppConfig 這樣的類,我們希望在程式運行期間只存在一個實體物件,
在 Python 中,我們可以用多種方法來實作單例模式:
1.使用模塊
可以參考自定義增刪改查組件site物件,很明顯的單利模式
其實,Python 的模塊就是天然的單例模式,因為模塊在第一次匯入時,會生成 .pyc 檔案,當第二次匯入時,就會直接加載 .pyc 檔案,而不會再次執行模塊代碼,因此,我們只需把相關的函式和資料定義在一個模塊中,就可以獲得一個單例物件了,如果我們真的想要一個單例類,可以考慮這樣做:
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
將上面的代碼保存在檔案 mysingleton.py 中,然后這樣使用:
from mysingleton import my_singleton
my_singleton.foo()
2.使用 new
from django.test import TestCase
# Create your tests here.
class Singleton:
def __init__(self,name):
self.name=name
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls)
return cls._instance
one = Singleton('aa')
two = Singleton('bb')
print(one.name)
print(one.name)
two.a = 3
print(one.a)
# one和two完全相同,可以用id(), ==, is檢測
print(id(one))
print(id(two))
print(one == two)
print(one is two)
加上鎖
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
print(self)
def __new__(cls, *args, **kwargs):
with cls._instance_lock:
if not hasattr(Singleton,'_instance'):
Singleton._instance=object.__new__(cls)
return Singleton._instance
def task():
obj = Singleton()
for i in range(10):
t=threading.Thread(target=task)
t.start()
3.利用類實作單例模式:
a.不能支持多執行緒的單例模式
class Singleton(object):
@classmethod
def instance(cls,*args,**kwargs):
if not hasattr(Singleton,'_instance'):
Singleton._instance=Singleton()
return Singleton._instance
a=Singleton.instance()
b=Singleton.instance()
print(a==b)#True
但是我們加上多執行緒試試
import time
class Singleton(object):
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls,*args,**kwargs):
if not hasattr(Singleton,'_instance'):
Singleton._instance=Singleton()
return Singleton._instance
# a=Singleton.instance()
# b=Singleton.instance()
# print(a==b)
import threading
def task():
obj = Singleton.instance()
print(obj)
for i in range(10):
t=threading.Thread(target=task)
t.start()
結果:
D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/單例模式/類.py
<__main__.Singleton object at 0x0000022E579C6E80>
<__main__.Singleton object at 0x0000022E579AB898>
<__main__.Singleton object at 0x0000022E579EC6A0>
<__main__.Singleton object at 0x0000022E579DB1D0>
<__main__.Singleton object at 0x0000022E579EC5C0>
<__main__.Singleton object at 0x0000022E579D1FD0>
<__main__.Singleton object at 0x0000022E579D9C50>
<__main__.Singleton object at 0x0000022E579C6F60>
<__main__.Singleton object at 0x0000022E579D1EB8>
<__main__.Singleton object at 0x0000022E579DB2B0>
Process finished with exit code 0
b.解決上面存在的問題,實作支持多執行緒的單列模式:
'''
遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333
尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書!
'''
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls,*args,**kwargs):
with cls._instance_lock:
if not hasattr(Singleton,'_instance'):
Singleton._instance=Singleton()
return Singleton._instance
return Singleton._instance
def task():
obj = Singleton.instance()
print(obj)
for i in range(10):
t=threading.Thread(target=task)
t.start()
結果:
D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flaskpro3/單例模式/類.py
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
<__main__.Singleton object at 0x000001BADB56F320>
Process finished with exit code 0
問題:
創建實體只能呼叫Singleton.instance()來呼叫,不能用Singleton()來實作
四、基于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步:執行Foodef __call__ 方法
obj()
class SingletonType(type):
def __init__(self,*args,**kwargs):
print(1)
super(SingletonType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs):
print(2)
obj = cls.__new__(cls,*args, **kwargs)
cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
return obj
class Foo(metaclass=SingletonType):
def __init__(self,name):
print(4)
self.name = name
def __new__(cls, *args, **kwargs):
print(3)
return object.__new__(cls)
obj1 = Foo('name')
實作單例
import threading
class Singleton(type):
_instance_lock=threading.Lock()
def __call__(cls, *args, **kwargs):
with cls._instance_lock:
if not hasattr(cls,'_instance'):
cls._instance=super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=Singleton):
def __init__(self,name):
self.name=name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/156182.html
標籤:Python
上一篇:Python基礎: 雙下方法
