Python 面試高頻問題:__Init__ 和__New__的區(qū)別
在Python類內(nèi)部定義,以_ _ xx _ _ 結(jié)尾的方法,都是類的內(nèi)置方法,也稱之為魔法方法。
類的內(nèi)置方法,會在某種條件滿足下自動觸發(fā),這里我們重點(diǎn)講解一下__init__和__new__,他們與實(shí)例創(chuàng)建有關(guān)。
簡述__init__
__init__(self): 這個方法我們相對較熟悉,他是python 類中默認(rèn)的初始化方法,即一個類實(shí)例化時,就會執(zhí)行的方法。
詳解__new__
__new__ 方法重寫非常固定,通常如下:
def __new__(cls):
return super().__new__(cls)
其中cls 代表類本身。
重寫__new__方法的代碼非常固定:重寫__new__方法一定要return super().__new__(cls),或者return object.__new__(cls)否則python解釋器會得不到分配了空間的對象引用,就不會調(diào)用對象的初始化方法。例如:
class Mycls:
def __new__(cls):
print('new')
return super().__new__(cls)
def __init__(self):
print('init')
my=Mycls()
輸出:
- new
- init
我們可以看到new 在init之前輸出,證明__new__(cls)在__init__(self)之前執(zhí)行。
我們重寫代碼:
def __new__(cls):
print('new')
my=Mycls()
print(my)
輸出:
- new
- None
可以看到如果__new__(cls):中沒有返回值,不會返回實(shí)例,__init__(self)將不會執(zhí)行。
__new__和__init__總結(jié)
1.__new__()方法用于創(chuàng)建實(shí)例,類實(shí)例化之前會首先調(diào)用,它是class的方法,是個靜態(tài)方法。而__init__()方法用戶初始化實(shí)例,該方法用在實(shí)例對象創(chuàng)建后被調(diào)用,它是實(shí)例對象的方法,用于設(shè)置類實(shí)例對象的一些初始值。
2.如果類中同時出現(xiàn)了__init__()方法和__new__()方法,則先調(diào)用__new__()方法后調(diào)用__init__()方法。__new__()方法是創(chuàng)建實(shí)例的第一步,執(zhí)行完了需要返回創(chuàng)建的類的實(shí)例,否則則報錯,無法執(zhí)行__init__()方法。其中,__init__()方法將不返回任何信息。
__new__的應(yīng)用
有的同學(xué)會問 用__new__來實(shí)現(xiàn)什么東東呢?
個人覺得,單例就是一個最經(jīng)典的應(yīng)用。單例模式(Singleton Pattern)是一種常用的軟件設(shè)計模式,該模式的主要目的是確保某一個類只有一個實(shí)例存在。當(dāng)我們希望在整個系統(tǒng)中,某個類只能出現(xiàn)一個實(shí)例時,單例對象就能派上用場。例如,一個系統(tǒng)中可以存在多個打印任務(wù),但是只能有一個正在工作的任務(wù);一個系統(tǒng)只能有一個窗口管理器或文件系統(tǒng);一個系統(tǒng)只能有一個計時工具或ID(序號)生成器。
具體實(shí)現(xiàn)代碼如下:
class Mycls:
_instance = None
def __new__(cls):
# 判斷該類的屬性是否為空;對第一個對象沒有被創(chuàng)建,我們應(yīng)該調(diào)用父類的方法,為第一個對象分配空間
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 __init__(self):
print('init')
my1=Mycls()
print(my1)
my2=Mycls()
print(my2)
輸出:
init
<__main__.Mycls object at 0x000000406E471148>
Init
<__main__.Mycls object at 0x000000406E471148>
可以看到雖然叫my1 和my2,但是他們都是對象0x000000406E471148,這就是單例模式的應(yīng)用。