python設計模式中的 單例模式:單例模式可以通過__new__ 方法實現,而__new__ 方法一般用于繼承不可變對象。
1、可變不可變對象
python中有可變對象和不可變對象兩種。前者創建后,可改變,地址卻不會改變,后者創建后都不能改變,一旦被改變了,就會產生一個新的對象。
class Mylist(object):
? ? def __init__(self,mylist_id,name=[ ]):
? ? ? ? self.mylist_id= mylist_id
? ? ? ? self.name= name
? ? def add_name(self,name):
? ? ? ? self.name.append(name)
mylist1= Mylist(1)
mylist1.add_name('zhangsan')
print(id(mylist1))
print(mylist1.name)
mylist2= Mylist(2)
mylist2.add_name('lisi')
print(id(mylist2))
print(mylist2.name)
print(id(mylist1.name))
print(id(mylist2.name))
結果圖:
有結果可知mylist1和mylist2的id號不一樣,在不同地址,但是mylist2可以在1的基礎上添加新的東西。這是因為 __init__函數在被創建的時候默認參數的值已經生成了往后繼續用的時候在是前者的基礎上,可以看到兩個mylist.name的地址是一樣的,所添加的名字在同一個地址里。
class Mylist(object):
? ? def __init__(self,mylist_id):
? ? ? ? self.mylist_id= mylist_id
? ? ? ? self.name= []
def add_name(self,name):
? ? ? ? self.name.append(name)
mylist1= Mylist(1)
mylist1.add_name('zhangsan')
print(id(mylist1))
print(mylist1.name)
mylist2= Mylist(2)
mylist2.add_name('lisi')
print(id(mylist2))
print(mylist2.name)
print(id(mylist1.name))
print(id(mylist2.name))
結果圖:
我們在__init__函數里面去掉name這個參數,self.name = [ ],相當于這個地方是空的,因為并沒有傳參。只有當調用add_name函數的時候在空列表里面添加名字,這時候不會因為創建__init__函數而產生默認緩存,導致每次在添加新內容都會在之前的緩存里面添加。這時兩個mylist.name的地址也是不一樣的。
2、__new__方法
這里涉及到一個__new__方法的使用,因為new方法正式用于繼承一些不可變的class時,__new__函數是分配地址空間的,創建對象的第一步,而__init__是初始化對象的,屬于第二步。__new__被定義為靜態方法,需要傳參數。需要返回值,返回的是實例化的實例,并且返回值是作為__init__的self參數傳入__init__函數。
class Test(object):
? ? def __init__(self):
? ? ? ? print('__init__()')
def __new__(cls):
? ? ? ? print('__new__()')
? ? ? ? return object.__new__(cls)
if __name__== '__main__':
? ? test= Test()
結果圖:
由此可以看出,實例化類時,先調用的是__new__函數,然后才是__init__函數
3、通過__new_-方法實現單例模式
單例模式:常見的一種軟件設計模式,主要目的是確保某一個類只有一個實例存在。
__new__方法可以用來實現設計模式中的單例模式,因為每次初始化實例對象的時候先調用的是__new__ 方法,我們需要對它重寫保證實現這個類只有一個實例存在。
class Singleton(object):
? ? def __new__(cls):
? ? ? ? # 用 hasattr 判斷類里是否有實例,如果沒有繼承之前的一個實例,如果沒有返回一個實例。
? ? ? ? if not hasattr(cls,'instance'):
? ? ? ? ? ? cls.instance= object.__new__(cls)
return cls.instance
# def __init__(self):
#? ? pass
test1= Singleton()
test2= Singleton()
print(test1)
print(test2)
print (test1is test2)
結果圖:
通過__new__ 方法的重寫,雖然實例化兩次,但是是同一個地址里面,保證了只有一個實例
我們把__new__ 方法注釋掉,直接用__init__方法:
class Singleton(object):
? ? # def __new__(cls):
? ? #? ? # 用 hasattr 判斷類里是否有實例,如果沒有繼承之前的一個實例,如果沒有返回一個實例。
? ? #? ? if not hasattr(cls, 'instance'):
#? ? ? ? cls.instance= object.__new__(cls)
#? ? return cls.instance
? ? def __init__(self):
pass
test1= Singleton()
test2= Singleton()
print(test1)
print(test2)
print (test1is test2)
結果圖:
沒有使用__new__方法重寫,直接用__init__時,就沒辦法保證有唯一的實例,實例化幾次就會產生幾個地址,并且不相同。
class Singleton(object):
? ? def __new__(cls):
? ? ? ? # 用 hasattr 判斷類里是否有實例,如果沒有繼承之前的一個實例,如果沒有返回一個實例。
? ? ? ? if not hasattr(cls,'instance'):
? ? ? ? ? ? cls.instance= object.__new__(cls)
return cls.instance
def __init__(self):
pass
? ? def action(self):
? ? ? ? return? id(self)
test1= Singleton()
test2= Singleton()
print(test1.action())
print(test2.action())
再試一次,增加一個新的方法 action( ),用來返回地址。通過結果可以看到,實例化兩次,action( )方法實現兩次,輸出兩次結果,但兩次輸出的地址還是一樣的。很明顯如果注釋掉__new__方法,那么地址是肯定不一樣的。這里單例模式就起到作用了。避免了同一個內容被多次使用后,每次都要占用不同的地址,浪費了資源。
以上就是python的單例模式。