python单例_Python单例模式
所謂單例,是指一個類的實例從始至終只能被創(chuàng)建一次,,而且自行實例化并向整個系統(tǒng)提供這個實例。
方法1
如果想使得某個類從始至終最多只有一個實例,使用__new__方法會很簡單。Python中類是通過__new__來創(chuàng)建實例的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
結果:
1
2
29922256 banana
29922256 banana
通過__new__方法,將類的實例在創(chuàng)建的時候綁定到類屬性_inst上。如果cls._inst為None,說明類還未實例化,實例化并將實例綁定到cls._inst,以后每次實例化的時候都返回第一次實例化創(chuàng)建的實例。注意從Singleton派生子類的時候,不要重載__new__。
方法2:
有時候我們并不關心生成的實例是否具有同一id,而只關心其狀態(tài)和行為方式。我們可以允許許多個實例被創(chuàng)建,但所有的實例都共享狀態(tài)和行為方式:
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 iin a, b, c:
adict[i]= j
j+= 1
for iin a, b, c:
print adict[i]
結果:
1
2
3
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 iin a, b, c:
adict[i]= j
j+= 1
for iin a, b, c:
print adict[i]
結果:
1
2
3
2
2
2
所有的實例都能當一個key使用了。
方法3
當你編寫一個類的時候,某種機制會使用類名字,基類元組,類字典來創(chuàng)建一個類對象。新型類中這種機制默認為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._instanceis 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)
結果:
1
34248016 34248016
id是相同的。
例子中我們構造了一個Singleton元類,并使用__call__方法使其能夠模擬函數(shù)的行為。構造類A時,將其元類設為Singleton,那么創(chuàng)建類對象A時,行為發(fā)生如下:
A=Singleton(name,bases,class_dict),A其實為Singleton類的一個實例。
創(chuàng)建A的實例時,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),這樣就將A的所有實例都指向了A的屬性_instance上,這種方法與方法1其實是相同的。
方法4
python中的模塊module在程序中只被加載一次,本身就是單例的。可以直接寫一個模塊,將你需要的方法和屬性,寫在模塊中當做函數(shù)和模塊作用域的全局變量即可,根本不需要寫類。
而且還有一些綜合模塊和類的優(yōu)點的方法:
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 namein self.__dict__:
raise self.ConstError
self.__dict__[name]= value
def __delattr__(self, name):
if namein self.__dict__:
raise self.ConstError
raise NameError
import sys
sys.modules[__name__]= _singleton()
python并不會對sys.modules進行檢查以確保他們是模塊對象,我們利用這一點將模塊綁定向一個類對象,而且以后都會綁定向同一個對象了。
將代碼存放在single.py中:
1
2
3
4
5
6
>>>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就是它自己類的唯一對象了。
更多
#-*- encoding=utf-8 -*-
print '----------------------方法1--------------------------'
#方法1,實現(xiàn)__new__方法#并在將一個類的實例綁定到類變量_instance上,#如果cls._instance為None說明該類還沒有實例化過,實例化該類,并返回#如果cls._instance不為None,直接返回cls._instance
classSingleton(object):def __new__(cls, *args, **kw):if not hasattr(cls, '_instance'):
orig=super(Singleton, cls)
cls._instance= orig.__new__(cls, *args, **kw)returncls._instanceclassMyClass(Singleton):
a= 1one=MyClass()
two=MyClass()
two.a= 3
printone.a#3#one和two完全相同,可以用id(), ==, is檢測
printid(one)#29097904
printid(two)#29097904
print one ==two#True
print one istwo#True
print '----------------------方法2--------------------------'
#方法2,共享屬性;所謂單例就是所有引用(實例、對象)擁有相同的狀態(tài)(屬性)和行為(方法)#同一個類的所有實例天然擁有相同的行為(方法),#只需要保證同一個類的所有實例具有相同的狀態(tài)(屬性)即可#所有實例共享屬性的最簡單最直接的方法就是__dict__屬性指向(引用)同一個字典(dict)#可參看:http://code.activestate.com/recipes/66531/
classBorg(object):
_state={}def __new__(cls, *args, **kw):
ob= super(Borg, cls).__new__(cls, *args, **kw)
ob.__dict__ =cls._statereturnobclassMyClass2(Borg):
a= 1one=MyClass2()
two=MyClass2()#one和two是兩個不同的對象,id, ==, is對比結果可看出
two.a = 3
printone.a#3
printid(one)#28873680
printid(two)#28873712
print one ==two#False
print one istwo#False#但是one和two具有相同的(同一個__dict__屬性),見:
print id(one.__dict__)#30104000
print id(two.__dict__)#30104000
print '----------------------方法3--------------------------'
#方法3:本質上是方法1的升級(或者說高級)版#使用__metaclass__(元類)的高級python用法
classSingleton2(type):def __init__(cls, name, bases, dict):
super(Singleton2, cls).__init__(name, bases, dict)
cls._instance=Nonedef __call__(cls, *args, **kw):if cls._instance isNone:
cls._instance= super(Singleton2, cls).__call__(*args, **kw)returncls._instanceclassMyClass3(object):__metaclass__ =Singleton2
one=MyClass3()
two=MyClass3()
two.a= 3
printone.a#3
printid(one)#31495472
printid(two)#31495472
print one ==two#True
print one istwo#True
print '----------------------方法4--------------------------'
#方法4:也是方法1的升級(高級)版本,#使用裝飾器(decorator),#這是一種更pythonic,更elegant的方法,#單例類本身根本不知道自己是單例的,因為他本身(自己的代碼)并不是單例的
def singleton(cls, *args, **kw):
instances={}def_singleton():if cls not ininstances:
instances[cls]= cls(*args, **kw)returninstances[cls]return_singleton
@singletonclassMyClass4(object):
a= 1
def __init__(self, x=0):
self.x=x
one=MyClass4()
two=MyClass4()
two.a= 3
printone.a#3
printid(one)#29660784
printid(two)#29660784
print one ==two#True
print one istwo#True
one.x = 1
printone.x#1
printtwo.x#1
總結
以上是生活随笔為你收集整理的python单例_Python单例模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python读取json文件转化为lis
- 下一篇: python还是hadoop_使用Pyt