Python中__new__方法有什么作用

本篇內(nèi)容介紹了“Python中__new__方法有什么作用”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

10余年的嘉善網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整嘉善建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“嘉善網(wǎng)站設(shè)計(jì)”,“嘉善網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

一、__new__方法簡介

接下來通過實(shí)例逐步詳細(xì)闡述__ new __ 方法在類初始化過程中是什么樣的存在!

1、初始化數(shù)據(jù)加載+解析類實(shí)例
class Solution(object):
 def __init__(self, name=None,data=None):
 self.name = name
 self.data = data
 #初始化加載數(shù)據(jù)
 self.xml_load(self.data)
 def xml_load(self,data):
 print("初始化init",data)
 def Parser(self):
 print("解析完成finish",self.name)
a = Solution(name="A111",data=10)
a.Parser()
b = Solution(name="A112",data=20)
b.Parser()
# print(a)與 print(b)返回了類的名稱和對象的地址
print(a)
print(b)
# 可以使用內(nèi)置函數(shù)id()查看python對象的內(nèi)存地址
print(id(a))
print(id(b))
初始化init 10
解析完成finish A111
初始化init 20
解析完成finish A1122517839809864
2517841042504

注:

1)、代碼實(shí)例化類過程

一般使用__init__()方法初始化一個(gè)類的實(shí)例,當(dāng)代碼中實(shí)例化一個(gè)類的時(shí)候,第一個(gè)調(diào)用執(zhí)行的是__new__()方法,當(dāng)定義的類中沒有重新定義__new__()方法時(shí)候,Python會默認(rèn)調(diào)用該父類的__new__()方法來構(gòu)造該實(shí)例,new方法就是先創(chuàng)建一個(gè)空間,然后每次創(chuàng)建一個(gè)實(shí)例化的對象,然后用開辟的空間存放這個(gè)實(shí)例化對象; 再次創(chuàng)建一個(gè)實(shí)例化的對象的時(shí)候,再用new方法開辟一個(gè)空間存放實(shí)例化對象。注意只有繼承了object的類才有此方法。

2)、內(nèi)存地址和對象可相互轉(zhuǎn)換

#通過_ctypes的api進(jìn)行對內(nèi)存地址的對象
import _ctypes
obj = _ctypes.PyObj_FromPtr(id(a))
#打印出來通過內(nèi)存地址尋找到的對象
print(obj)

print(id(a))與 print(id(b))打印出來的都是內(nèi)存地址(10進(jìn)制),print(a)與 print(b)返回了類的名稱和對象的地址,但是兩者并不相同。每次實(shí)例化類都會創(chuàng)建分配不同的對象地址,因此,代碼實(shí)例化類過程中返回類對象的地址引用也就不同。

2、初始化數(shù)據(jù)加載重寫new方法+解析類實(shí)例
class Solution:
 """
 注:new方法是為實(shí)例化對象創(chuàng)建空間的方法,現(xiàn)在new方法被改寫,沒有將實(shí)例化對象引用返回給python的解釋器
 無法為實(shí)例化對象創(chuàng)建空間存儲,所以運(yùn)行代碼會報(bào)錯(cuò)。也沒有完成初始化操作。
 """
 def __new__(cls, *args, **kwargs):
 print("對象創(chuàng)建空間")
 cls.instance = super().__new__(cls)
 print(cls.instance)
 # return cls.instance #若未返回實(shí)例對象引用,實(shí)例化方法將報(bào)錯(cuò):AttributeError: 'NoneType' object has no attribute 'Parser'
 def __init__(self,name,data):
 self.name = name
 self.data = data
 self.xml_load(self.data)
 def xml_load(self,data):
 print("初始化init", data)
 def Parser(self):
 print("解析完成finish",self.data)
a = Solution("A111",10)
a.Parser()
print(id(a))

注:

1)、__init__()方法和__new__()方法區(qū)別

__new__()方法用于創(chuàng)建實(shí)例,類實(shí)例化之前會首先調(diào)用,它是class的方法,是個(gè)靜態(tài)方法。而__init__()方法用戶初始化實(shí)例,該方法用在實(shí)例對象創(chuàng)建后被調(diào)用,它是實(shí)例對象的方法,用于設(shè)置類實(shí)例對象的一些初始值。

如果類中同時(shí)出現(xiàn)了__init__()方法和__new__()方法,則先調(diào)用__new__()方法后調(diào)用__init__()方法。__new__()方法是創(chuàng)建實(shí)例的第一步,執(zhí)行完了需要返回創(chuàng)建的類的實(shí)例,否則則報(bào)錯(cuò),無法執(zhí)行__init__()方法。其中,__init__()方法將不返回任何信息。

2)、重寫__new__()方法

def __new__(cls, *args, **kwargs):
 print(cls)# cls 代表的是Solution這個(gè)類本身cls.instance = super().__new__(cls)# object().__ new __()
 print(cls.instance)
 return cls.instance

super()與object.__new__(cls)都是在調(diào)用父類的new方法,必須把父類的new方法返回給函數(shù),才能開辟空間,因此必須添加return。代碼的執(zhí)行順序是:先執(zhí)行new方法,然后執(zhí)行init方法,最后是其它方法。

二、單例模式

單例模式最初的定義出現(xiàn)于《設(shè)計(jì)模式》:“保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)?!?/p>

單例的使用主要是在需要保證全局只有一個(gè)實(shí)例可以被訪問的情況,比如系統(tǒng)日志的輸出、操作系統(tǒng)的任務(wù)管理器等。

1、用new方法如何實(shí)現(xiàn)單例模式?
class Solution:
 # 1、記錄第一個(gè)被創(chuàng)建對象的引用,代表著類的私有屬性
 _instance = None # 靜態(tài)變量 存儲在類的命名空間里的
 def __init__(self,name,data):
 self.name = name
 self.data = data
 self.xml_load(self.data)
 def __new__(cls, *args, **kwargs):
 # 2.判斷該類的屬性是否為空;對第一個(gè)對象沒有被創(chuàng)建,我們應(yīng)該調(diào)用父類的方法,為第一個(gè)對象分配空間
 if cls._instance == None:
 # 3.把類屬性中保存的對象引用返回給python的解釋器
 cls._instance = object.__new__(cls)# 3
 return cls._instance
 # 如果cls._instance不為None,直接返回已經(jīng)實(shí)例化了的實(shí)例對象
 else:
 return cls._instance# 必須把地址返回給new方法,讓它有存儲空間
 def xml_load(self,data):
 print("初始化init",self.name,data)
 def Parser(self):
 print("解析完成finish",self.name)
a = Solution("A11",10)#第一次開辟一個(gè)對象空間地址,后面創(chuàng)建都是在該地址上進(jìn)行的
a.Parser()
b = Solution("A12",20)#b把a(bǔ)覆蓋掉
b.Parser()
print(id(a))
print(id(b))
# 內(nèi)存地址,而且它們的內(nèi)存地址都是一樣的
print(a.name)
print(b.name)
初始化init A11 10
解析完成finish A11
初始化init A12 10
解析完成finish A12
2465140199816
2465140199816
A12
A12

注:

1)、單例模式始終只有一個(gè)空間,該空間一直重復(fù)利用。

首先定義一個(gè)類的私有屬性_instance,用來記錄第一個(gè)被創(chuàng)建對象的引用,如果cls._instance為None說明該類還沒有實(shí)例化過,則實(shí)例化該類并返回實(shí)例對象。

通過以下數(shù)據(jù)測試可知,print(obj.name, obj.data)最后打印出來的都是A12,第一次打印"A11"時(shí),屬性為空,執(zhí)行if語句開辟了一個(gè)空間存放該屬性;從 第二次打已經(jīng)開辟了空間 ,執(zhí)行else語句,直接返回"A12"到原來的空間中,把前面的蓋數(shù)據(jù)覆蓋掉。

def task(id,data):
 obj = Solution("{0}".format(id), "{0}".format(data))
 print(obj.name, obj.data)
import threading
ID=["A11","A12","A13","A14","A12"]
DATA=[10,20,30,40,20]
for i in range(5):
 t = threading.Thread(target=task(ID[i],DATA[i]), args=[i, ])
 t.start()
初始化init A11 10
A11 10
初始化init A12 20
A12 20
初始化init A13 30
A13 30
初始化init A14 40
A14 40
初始化init A12 20
A12 20

2)、單例模式另外一種實(shí)現(xiàn)方法

def __new__(cls,*args,**kwargs):
 # hasattr查詢目標(biāo)并判斷有沒有,not1==1返回的是False
 # if語句后面的
 # not 條件整體為True時(shí),執(zhí)行cls.instance = object....代碼
 # if語句后面的
 # not 條件整體為False時(shí),執(zhí)行return代碼
 if not hasattr(cls,"instance"): # hasattr查、判斷的作用
 cls.instance = object.__new__(cls)
 return cls.instance
2、如何控制類僅執(zhí)行一次初始化方法?

以上實(shí)現(xiàn)了單例模式對象空間的重復(fù)利用,但是有時(shí)候我們想初始化過程只加載一次,避免頻繁請求浪費(fèi)系統(tǒng)資源(如數(shù)據(jù)庫連接請求數(shù)據(jù))。

class Solution:
 #定義類變量
 # 記錄第一個(gè)被創(chuàng)建對象的引用,代表著類的私有屬性
 _instance = None
 #記錄是否執(zhí)行過初始化動(dòng)作
 init_flag = False
 def __init__(self,name,data):
 self.name = name
 self.data = data
 #使用類名調(diào)用類變量,不能直接訪問。
 if Solution.init_flag:
 return
 self.xml_load(self.data)
 # 修改類屬性的標(biāo)記
 Solution.init_flag = True
 def __new__(cls, *args, **kwargs):
 # 判斷該類的屬性是否為空;對第一個(gè)對象沒有被創(chuàng)建,我們應(yīng)該調(diào)用父類的方法,為第一個(gè)對象分配空間
if cls._instance == None:
 # 把類屬性中保存的對象引用返回給python的解釋器
 cls._instance = object.__new__(cls)
 return cls._instance
 #如果cls._instance不為None,直接返回已經(jīng)實(shí)例化了的實(shí)例對象
 else:
return cls._instance
 def xml_load(self,data):
 print("初始化init",self.name,data)
 def Parser(self):
 print("解析完成finish",self.name)
a = Solution("A11",10)#第一次實(shí)例化對象地址,后面創(chuàng)建都是在該地址上進(jìn)行的
a.Parser()
b = Solution("A12",20)#b把a(bǔ)覆蓋掉
b.Parser()
print(id(a))
print(id(b))
print(a.name)
print(b.name)
初始化init A11 10
解析完成finish A11
解析完成finish A12
2280855720328
2280855720328
A12
A12

注:

1)、單例模式下僅加載一次初始化過程。

這時(shí)候我們在類空間中再添加一個(gè)init_flag屬性來記錄是否已經(jīng)執(zhí)行過初始化操作即可實(shí)現(xiàn)加載一次初始化過程。從以上兩次實(shí)例化過程結(jié)果來看,對象引用地址不變,結(jié)果被最后一次實(shí)例化數(shù)據(jù)覆蓋且初始化init只被打印一次。

2)、單例模式下一次資源加載注意點(diǎn)

單例模式下控制類僅進(jìn)行一次初始化過程適用于資源一次性加載進(jìn)緩存的過程,對于多進(jìn)程應(yīng)用可采用多例模式實(shí)現(xiàn)。

三、多例模式

多個(gè)實(shí)例對象空間引用地址完全獨(dú)立,從而保持避免不同請求資源不被占用。將同一個(gè)對象請求歸為同一個(gè)實(shí)例。

class Solution:
 ##定義類實(shí)例化對象字典,即不同的實(shí)例對象對應(yīng)不同的對象空間地址引用
 _loaded = {}
 def __init__(self,name,data):
 self.name = name
 self.data = data
 self.xml_load(self.data)
 def __new__(cls, name,*args):
 if cls._loaded.get(name) is not None:
 client = cls._loaded.get(name)
 print(f"已經(jīng)存在訪問對象 {name}")
 print(client)
 return client
 # 把類屬性中保存的對象引用返回給python的解釋器
 print(f"正在創(chuàng)建訪問對象 {name}")
 client = super().__new__(cls)
 # 為該類實(shí)例name添加一個(gè)空間對象地址引用
 print(client)
 cls._loaded[name] = client
 return client
 def xml_load(self,data):
 print("初始化init",self.name,data)
 def Parser(self):
 print("解析完成finish",self.name)
if __name__ == '__main__':
 print("多例模式實(shí)例")
 a = Solution("A11",10)
 a.Parser()
 b = Solution("A11",10)
 b.Parser()
 c = Solution("A12", 20)
 c.Parser()
 print(f"{a is b}")
 print(a.name)
 print(b.name)
 print(c.name)

注:

1)、多例模式始終具有多個(gè)空間,不同空間完全獨(dú)立。

我們在類空間中定義類實(shí)例化對象字典,即建立不同的實(shí)例對象和對象空間地址引用鍵值對,從而實(shí)現(xiàn)多例模式。通過類字典判斷實(shí)例對象是否創(chuàng)建,節(jié)省創(chuàng)建的成本。

2)、多例模式測試過程

當(dāng)創(chuàng)建相同的實(shí)例對象name="A11"時(shí),程序首先在實(shí)例池中搜索cls._loaded.get(name),若存在則直接返回已創(chuàng)建的實(shí)例對象空間。多例模式完美的實(shí)現(xiàn)了不同訪問對象具體不同的實(shí)例化對象地址。

多例模式實(shí)例
正在創(chuàng)建訪問對象 A11初始化init A11 10
解析完成finish A11
已經(jīng)存在訪問對象 A11初始化init A11 10
解析完成finish A11
正在創(chuàng)建訪問對象 A12初始化init A12 20
解析完成finish A12
True
A11
A11
A12

3)、多例模式下緩沖機(jī)制的實(shí)現(xiàn)

進(jìn)一步優(yōu)化多例模式初始化過程,比如讀取文件或者數(shù)據(jù)庫時(shí)僅進(jìn)行一次初始化加載。

class Solution:
 ##定義類實(shí)例化對象字典,即不同的實(shí)例對象對應(yīng)不同的對象空間地址引用
 _loaded = {}
 def __new__(cls, name,data,*args):
 if cls._loaded.get(name) is not None:
 client = cls._loaded.get(name)
 print(f"已經(jīng)存在訪問對象 {name}")
 print(client)
 return client
 print(f"正在創(chuàng)建訪問對象 {name}")
 # 把類屬性中保存的對象引用返回給python的解釋器
 client = super().__new__(cls)
 print(client)
 # 為該類實(shí)例name添加一個(gè)空間對象地址引用
 cls._loaded[name] = client
 client._init_db(name,data)
 return client
 def _init_db(self,name,data):
 self.name = name
 self.data = data
 self.xml_load(self.data)
 def xml_load(self,data):
 print("初始化init",self.name,data)
 def Parser(self):
 print("解析完成finish",self.name)
if __name__ == '__main__':
 print("多例模式實(shí)例-緩存")
 a = Solution("A11",10)
 a.Parser()
 b = Solution("A11",10)
 b.Parser()
 c = Solution("A12", 20)
 c.Parser()
 print(f"{a is b}")
 print(a.name)
 print(b.name)
 print(c.name)
多例模式實(shí)例
正在創(chuàng)建訪問對象 A11初始化init A11 10
解析完成finish A11
已經(jīng)存在訪問對象 A11解析完成finish A11
正在創(chuàng)建訪問對象 A12初始化init A12 20
解析完成finish A12
True
A11
A11
A12

注:多例模式下多個(gè)實(shí)例化對象均只進(jìn)行一次初始化過程。

重寫__new__方法中每個(gè)實(shí)例對象創(chuàng)建后綁定初始化_init_db()方法執(zhí)行一次,后面遇到同一個(gè)實(shí)例對象將不會發(fā)生什么,直接返回已創(chuàng)建的實(shí)例對象。從測試結(jié)果來看,創(chuàng)建相同的實(shí)例對象name="A11"時(shí),第二次將略過初始化數(shù)據(jù)加載過程,很好的實(shí)現(xiàn)了緩存機(jī)制。

“Python中__new__方法有什么作用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

當(dāng)前文章:Python中__new__方法有什么作用
文章路徑:http://bm7419.com/article8/pcdgip.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃網(wǎng)站制作、響應(yīng)式網(wǎng)站、自適應(yīng)網(wǎng)站、全網(wǎng)營銷推廣、移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)