單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個伺服器程式的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息 ...
單例模式(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)