所謂單例,是指乙個類的例項從始至終只能被建立一次。
方法1
如果想使得某個類從始至終最多只有乙個例項,使用__new__方法會很簡單。python中類是通過__new__來建立例項的:
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
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:
有時候我們並不關心生成的例項是否具有同一id,而只關心其狀態和行為方式。我們可以允許許多個例項被建立,但所有的例項都共享狀態和行為方式:
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:
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
12
如果這種行為不是你想要的,可以為borg類新增__eq__和__hash__方法,使其更接近於單例模式的行為:
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
22
所有的例項都能當乙個key使用了。
方法3
當你編寫乙個類的時候,某種機制會使用類名字,基類元組,類字典來建立乙個類物件。新型類中這種機制預設為type,而且這種機制是可程式設計的,稱為元類__metaclass__ 。
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在程式中只被載入一次,本身就是單例的。可以直接寫乙個模組,將你需要的方法和屬性,寫在模組中當做函式和模組作用域的全域性變數即可,根本不需要寫類。
而且還有一些綜合模組和類的優點的方法:
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中:
>>> import single
>>> single.a=1
>>> single.a=2
consterror
>>> del single.a
consterror
方法5
最簡單的方法:
class singleton(object):
pass
singleton = singleton()
將名字singleton繫結到例項上,singleton就是它自己類的唯一物件了。
python單例模式繼承 python單例模式
我們可以使用 new 這個特殊方法。該方法可以建立乙個其所在類的子類的物件。更可喜的是,我們的內建 object 基類實現了 new 方法,所以我們只需讓 sing 類繼承 object 類,就可以利用 object 的 new 方法來建立 sing 物件了。classsing object def...
單例模式 python
單例模式 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。實現 某個類只有乙個例項 途徑 1 讓乙個全域性變數使得乙個物件被訪問,但是它不能防止外部例項化多個物件。2 讓類自身負責儲存它的唯一例項。這個類可以保證沒有其他例項可以被建立。即單例模式。多執行緒時的單例模式 加鎖 雙重鎖定。餓漢式...
python單例模式
new 在 init 之前被呼叫,用於生成例項物件。利用這個方法和類的屬性的特點可以實現設計模式的單例模式。單例模式是指建立唯一物件,單例模式設計的類只能例項 例項化1個物件。class singleton object instance none def init self pass def ne...