Python單例模式

2021-09-08 10:23:04 字數 4515 閱讀 9382

所謂單例,是指乙個類的例項從始至終只能被建立一次。

方法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...