五種單例模式----來自腳本之家
本文為大家分享了Python創建單例模式的5種常用方法,供大家參考,具體內容如下
所謂單例,是指一個類的實例從始至終只能被創建一次。
方法1:
如果想使得某個類從始至終最多只有一個實例,使用__new__方法會很簡單。Python中類是通過__new__來創建實例的:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Singleton( object ):
def __new__( cls , * args, * * kwargs):
if not hasattr ( cls , ‘_inst‘ ):
cls ._inst = super (Singleton, cls ).__new__( cls , * args, * * kwargs)
return cls ._inst
if __name__ = = ‘__main__‘ :
class A(Singleton):
def __init__( self ,s):
self .s = s
a = A( ‘apple‘ )
b = A( ‘banana‘ )
print id (a),a.s
print id (b),b.s
|
結果:
29922256 banana
29922256 banana
通過__new__方法,將類的實例在創建的時候綁定到類屬性_inst上。如果cls._inst為None,說明類還未實例化,實例化並將實例綁定到cls._inst,以後每次實例化的時候都返回第一次實例化創建的實例。註意從Singleton派生子類的時候,不要重載__new__。
方法2:
1 2 3 4 5 6 |
class Borg( object ):
_shared_state = {}
def __new__( cls , * args, * * kwargs):
obj = super (Borg, cls ).__new__( cls , * args, * * kwargs)
obj.__dict__ = cls ._shared_state
return obj
|
將所有實例的__dict__指向同一個字典,這樣實例就共享相同的方法和屬性。對任何實例的名字屬性的設置,無論是在__init__中修改還是直接修改,所有的實例都會受到影響。不過實例的id是不同的。要保證類實例能共享屬性,但不和子類共享,註意使用cls._shared_state,而不是Borg._shared_state。
因為實例是不同的id,所以每個實例都可以做字典的key:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
if __name__ = = ‘__main__‘ :
class Example(Borg):
pass
a = Example()
b = Example()
c = Example()
adict = {}
j = 0
for i in a,b,c:
adict[i] = j
j + = 1
for i in a,b,c:
print adict[i]
|
結果:
0
1
2
如果這種行為不是你想要的,可以為Borg類添加__eq__和__hash__方法,使其更接近於單例模式的行為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class Borg( object ):
_shared_state = {}
def __new__( cls , * args, * * kwargs):
obj = super (Borg, cls ).__new__( cls , * args, * * kwargs)
obj.__dict__ = cls ._shared_state
return obj
def __hash__( self ):
return 1
def __eq__( self ,other):
try :
return self .__dict__ is other.__dict__
except :
return False
if __name__ = = ‘__main__‘ :
class Example(Borg):
pass
a = Example()
b = Example()
c = Example()
adict = {}
j = 0
for i in a,b,c:
adict[i] = j
j + = 1
for i in a,b,c:
print adict[i]
|
結果:
2
2
2
所有的實例都能當一個key使用了。
方法3
當你編寫一個類的時候,某種機制會使用類名字,基類元組,類字典來創建一個類對象。新型類中這種機制默認為type,而且這種機制是可編程的,稱為元類__metaclass__ 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Singleton( type ):
def __init__( self ,name,bases,class_dict):
super (Singleton, self ).__init__(name,bases,class_dict)
self ._instance = None
def __call__( self , * args, * * kwargs):
if self ._instance is None :
self ._instance = super (Singleton, self ).__call__( * args, * * kwargs)
return self ._instance
if __name__ = = ‘__main__‘ :
class A( object ):
__metaclass__ = Singleton
a = A()
b = A()
print id (a), id (b)
|
結果:
34248016 34248016
id是相同的。
例子中我們構造了一個Singleton元類,並使用__call__方法使其能夠模擬函數的行為。構造類A時,將其元類設為Singleton,那麽創建類對象A時,行為發生如下:
A=Singleton(name,bases,class_dict),A其實為Singleton類的一個實例。
創建A的實例時,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),這樣就將A的所有實例都指向了A的屬性_instance上,這種方法與方法1其實是相同的。
方法4
python中的模塊module在程序中只被加載一次,本身就是單例的。可以直接寫一個模塊,將你需要的方法和屬性,寫在模塊中當做函數和模塊作用域的全局變量即可,根本不需要寫類。
而且還有一些綜合模塊和類的優點的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class _singleton( object ):
class ConstError(TypeError):
pass
def __setattr__( self ,name,value):
if name in self .__dict__:
raise self .ConstError
self .__dict__[name] = value
def __delattr__( self ,name):
if name in self .__dict__:
raise self .ConstError
raise NameError
import sys
sys.modules[__name__] = _singleton()
|
python並不會對sys.modules進行檢查以確保他們是模塊對象,我們利用這一點將模塊綁定向一個類對象,而且以後都會綁定向同一個對象了。
將代碼存放在single.py中:
1 2 3 |
>>> import single
>>> single.a = 1
>>> single.a = 2
|
ConstError
>>> del single.a
ConstError
方法5:
最簡單的方法:
1 2 3 |
class singleton( object ):
pass
singleton = singleton()
|
將名字singleton綁定到實例上,singleton就是它自己類的唯一對象了。
以上就是Python單例模式的實現方式詳細介紹,希望對大家的學習有所幫助。
五種單例模式----來自腳本之家