單例是什么?
單例模式,也叫單子模式,是一種常用的軟件設(shè)計模式。在應(yīng)用這個模式時,單例對象的類必須保證只有一個實例存在。許多時候整個系統(tǒng)只需要擁有一個的全局對象,這樣有利于我們協(xié)調(diào)系統(tǒng)整體的行為。
簡單來說,就是某種類,它有且就有一個實例。
在Python中怎么實現(xiàn)
重寫__new__方法
__new__是類在創(chuàng)建時(不是實例化)時會調(diào)用的成員方法,其參數(shù)是這個類本身,即cls。這里我們使用hasattr方法來判斷一個類有沒有實例。如果沒有就新建一個,有的話就返回當(dāng)前的那個。這樣就保證了這個類永遠(yuǎn)只會有一個實例。
# singleton
class Singleton(object):
def __new__(cls):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
class MyClass(Singleton):
a = 1
A = MyClass()
B = MyClass()
print (A is B)
裝飾器實現(xiàn)
這個方法的核心思想就是將對象的實例用其他的容器保存下來,每次實例類的時候,裝飾器會判斷這個類是不是已經(jīng)在容器中了。如果是,則直接返回容器中的實例,否則則新建一個實例返回并放入容器中。容器中最多只會有一個值。
# singleton
def singleton(cls):
instances = {}
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance
@singleton
class MyClass():
a = 1
A = MyClass()
B = MyClass()
print (A is B)
用list 也可以
# singleton
def singleton(cls):
instances = []
def getinstance(*args, **kwargs):
if not instances:
instances.append(cls(*args, **kwargs))
return instances[0]
return getinstance
@singleton
class MyClass():
a = 1
A = MyClass()
B = MyClass()
#print (len(A))
print (A is B)
這樣也可以
# singleton
instances = None
def singleton(cls):
def getinstance(*args, **kwargs):
global instances
if not instances:
instances = cls(*args, **kwargs)
return instances
return getinstance
@singleton
class MyClass():
a = 1
A = MyClass()
B = MyClass()
#print (len(A))
print (A is B)
但是這樣不行
# singleton
def singleton(cls):
instance = None
def getinstance(*args, **kwargs):
if not instance:
instance = cls(*args, **kwargs)
return instance
return getinstance
@singleton
class MyClass():
a = 1
A = MyClass()
B = MyClass()
#print (len(A))
print (A is B)
為什么?因為這里構(gòu)成了閉包,Python只會會把閉包中用到的值保存下來,但是你不能在閉包中對其進(jìn)行修改。也就是說在這個例子里,你只能訪問instance,但是不能對其賦值,否則會報錯UnboundLocalError。我會在另外一篇關(guān)于作用域和閉包的文章中仔細(xì)講一講。
怎么改呢?一種就是用上面的兩種方法,將它改成一個列表或者字典,我們不能對列表本身做修改,但是可以對列表中包含的對象做修改;另一種方法則是用關(guān)鍵詞nonlocal:
# singleton
def singleton(cls):
instance = None
def getinstance(*args, **kwargs):
nonlocal instance
if not instance:
instance = cls(*args, **kwargs)
return instance
return getinstance
@singleton
class MyClass():
a = 1
A = MyClass()
B = MyClass()
#print (len(A))
print (A is B)