深入理解Python中的 __new__ 和 __init__及區(qū)別介紹
本文的目的是討論P(yáng)ython中 __new__ 和 __ini___ 的用法。 __new__ 和 __init__ 的區(qū)別主要表現(xiàn)在:1. 它自身的區(qū)別;2. 及在Python中新式類和老式類的定義。
理解 __new__ 和 __init__ 的區(qū)別
這兩個(gè)方法的主要區(qū)別在于:__new__ 負(fù)責(zé)對(duì)象的創(chuàng)建而 __init__ 負(fù)責(zé)對(duì)象的初始化。在對(duì)象的實(shí)例化過(guò)程中,這兩個(gè)方法會(huì)有些細(xì)微的差別,表現(xiàn)于:如何工作,何時(shí)定義。
Python中兩種類的定義方式
Python 2.x 中類的定義分為新式定義和老式定義兩種。老式的類出現(xiàn)在Python 3之前且定義時(shí)不繼承自'object' 基類,默認(rèn)是繼承自'type' :而新式類在定義時(shí)顯示地繼承'object'類。
Python 2.x中老式類的定義:
class A: # -> inherits from type pass
Python 2.x中新式類的定義:
class A(object): # -> clearly inherits from object pass
在Python 3.x中沒(méi)有新式類和老式類之分,它們都繼承自'object' 類。因此可以不用顯示地指定其基類。'object'基類中擁有的方法和屬性可通用于所有的新式類。
下文中我們將通過(guò)測(cè)試 __new__ 和 __init__ 在各個(gè)case中的用法,來(lái)逐步剖析它們的功能和區(qū)別,并以此確實(shí)我們?cè)撊绾问褂盟鼈儭?/p>
分析不同的Case
在研究具體的實(shí)現(xiàn)之前,我們應(yīng)該知道 __new__ 方法只接受 cls 作為它的第一個(gè)參數(shù),而 __init__ 一個(gè)參數(shù)是 self (__new__ 是一個(gè)類方法,而__init__ 是一個(gè)對(duì)象方法)。因?yàn)槲覀冋{(diào)用 __new__ 之前連實(shí)例都還沒(méi)有,因此那時(shí)根本沒(méi)有 self 的存在。__init__ 在 使用 __new__ 創(chuàng)建并返回一個(gè)實(shí)例之后調(diào)用,因此可將返回的實(shí)例通過(guò)self傳遞給它。
老式類中的__new__ 和 __init__
老式類中其實(shí)并沒(méi)有 __new__ 方法,因?yàn)?__init__ 就是它的構(gòu)造方法(函數(shù))。因此如果我們有下面這段代碼:
class A:
def __new__(cls): print "A.__new__ is called" # -> this is never called
A()
這個(gè)case中的 __new__ 方法將永遠(yuǎn)不會(huì)執(zhí)行,因?yàn)樗皇抢鲜筋惖哪繕?biāo)函數(shù)。
如果我們是重寫(xiě)一個(gè)__init__ 方法:
class A:
def __init__(self): print "A.__init__ called"
A()
它將會(huì)輸出:
A.__init__ called
我們嘗試從 __init__ 方法中返回一個(gè)值:
class A:
def __init__(self): return 29
A()
將會(huì)產(chǎn)生一個(gè)錯(cuò)誤:
TypeError: __init__() should return None
這意味著我們實(shí)例化一個(gè)老式類的對(duì)象時(shí),不能控制它返回什么內(nèi)容。
新式類中的 __new__ 和 __init__
新式類允許開(kāi)發(fā)者根據(jù)他們的意圖來(lái)重寫(xiě) __new__ 和 __init__ 方法。__new__ (構(gòu)造函數(shù))單獨(dú)地創(chuàng)建一個(gè)對(duì)象,而 __init__ (初始化函數(shù))負(fù)責(zé)初始化這個(gè)對(duì)象。
我們看一下下面這個(gè)case的執(zhí)行順序:
class A(object): # -> don t forget the object specified as base def __new__(cls): print "A.__new__ called" return super(A, cls).__new__(cls) def __init__(self): print "A.__init__ called"
A()
將會(huì)輸出:
A.__new__ called
A.__init__ called
你可能想要問(wèn) __init__ 和 __new__ 是在哪里被調(diào)用的,我能告訴你的是: __new__ 是在我們調(diào)用類名進(jìn)行實(shí)例化時(shí)自動(dòng)調(diào)用的,__init__ 是在這個(gè)類的每一次實(shí)例化對(duì)象之后調(diào)用的,__new__ 方法創(chuàng)建一個(gè)實(shí)例之后返回這個(gè)實(shí)例對(duì)象并傳遞給 __init__ 方法的 self 參數(shù)。因此,即使你將創(chuàng)建的實(shí)例對(duì)象保存成一個(gè)全局或靜態(tài)的變量,并且每次調(diào)用__new__ 方法時(shí)都返回這個(gè)對(duì)象,__init__ 方法依然每次都會(huì)被調(diào)用。這意味著如果我們?cè)?__new__ 中省略調(diào)用基類的super(A, cls).__new__(cls) 代碼,__init__ 方法將不會(huì)被執(zhí)行。我們一起看一下這個(gè)case的代碼:
class A(object):
def __new__(cls): print "A.__new__ called" def __init__(self): print "A.__init__ called" # -> is actually never called print A()
輸出的內(nèi)容如下:
A.__new__ called
None
Obviously the instantiation is evaluated to None since we don't return anything from the constructor.
顯然這個(gè)實(shí)例被認(rèn)定None,如果我們沒(méi)有在構(gòu)造函數(shù)中返回任何對(duì)象。
想像一下,如果我們從 __new__ 中返回一些其他東西(對(duì)象)將會(huì)發(fā)生什么,如下面這樣:
class A(object):
def __new__(cls): print "A.__new__ called" return 29
print A()
猜想會(huì)輸出如下的內(nèi)容:
A.__new__ called
29
我們?cè)倏匆幌聫?__init__ 中返回一個(gè)對(duì)象將會(huì)發(fā)生什么:
class A(object):
def __init__(self): print "A.__init__ called" return 33 # -> TypeError: __init__ should return None
A()
這將會(huì)出現(xiàn)警告:
TypeError: __init__ should return None
在調(diào)用 __init__ 時(shí)會(huì)出現(xiàn)一個(gè)TypeError的異常:__init__() should return None, not ‘int'
。這主要是因?yàn)?__init__ 的作用只是刷新和更改剛創(chuàng)建的這個(gè)實(shí)例對(duì)象的狀態(tài)。
新式的類在靈活性上提供了更多的功能,允許我們?cè)跇?gòu)造和初始化的級(jí)別做更多預(yù)處理和后處理的操作,讓我們可以在實(shí)例化時(shí)控制我們想要返回的內(nèi)容。
考慮到這一點(diǎn),我們嘗試一下在 __new__ 中返回一個(gè)其他類的對(duì)象。
首先,我們定義一個(gè)待用的類:
class Sample(object):
def __str__(self): return "SAMPLE"
然后,再定義一個(gè)重寫(xiě) __new__ 方法的類:
class A(object):
def __new__(cls): return Sample()
也可以寫(xiě)成下面這樣:
class A(object):
def __new__(cls): return super(A, cls).__new__(Sample)
最后,我們調(diào)用A()來(lái)創(chuàng)建一個(gè)對(duì)象,并打印該對(duì)象:
print A()
這將會(huì)輸出:
SAMPLE
總結(jié)
以上所述是小編給大家介紹的Python中的 __new__ 和 __init__及區(qū)別介紹,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- 詳解Python中的__init__和__new__
- python中的__init__ 、__new__、__call__小結(jié)
- Python中__init__和__new__的區(qū)別詳解
- Python中__new__與__init__方法的區(qū)別詳解
- 淺談python中的__init__、__new__和__call__方法
- Python函數(shù)__new__及__init__作用及區(qū)別解析
- Python中__new__和__init__的區(qū)別與聯(lián)系
- Python中class內(nèi)置方法__init__與__new__作用與區(qū)別解析
- python __init__與 __new__的區(qū)別
- 詳解Python中__new__和__init__的區(qū)別與聯(lián)系
- python中__new__和__init__的實(shí)現(xiàn)
相關(guān)文章
Python實(shí)現(xiàn)對(duì)Excel表格的操作詳解
這篇文章主要介紹了Python實(shí)現(xiàn)對(duì)Excel表格的操作,在數(shù)據(jù)處理和報(bào)告生成等工作中,Excel表格是一種常見(jiàn)且廣泛使用的工具,使用Python來(lái)處理Excel表格能夠大大的提升效率,感興趣的同學(xué)可以參考下2024-02-02python實(shí)現(xiàn)TCP文件接收發(fā)送
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)TCP文件接收發(fā)送,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09python實(shí)現(xiàn)csdn全部博文下載并轉(zhuǎn)PDF
我們學(xué)習(xí)編程,在學(xué)習(xí)的時(shí)候,會(huì)有想把有用的知識(shí)點(diǎn)保存下來(lái),我們可以把知識(shí)點(diǎn)的內(nèi)容爬下來(lái)轉(zhuǎn)變成pdf格式,方便我們拿手機(jī)可以閑時(shí)翻看,是很方便的,本文就介紹一下如何實(shí)現(xiàn)2021-06-06Python線程創(chuàng)建和終止實(shí)例代碼
這篇文章主要介紹了Python線程創(chuàng)建和終止實(shí)例代碼,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01Python實(shí)現(xiàn)生成多種有規(guī)律的數(shù)字序列
在?Python?編程中,生成數(shù)字序列是一項(xiàng)常見(jiàn)且重要的任務(wù),本文將深入探討如何使用Python中的內(nèi)置函數(shù)、列表推導(dǎo)式、生成器等方式來(lái)生成多種有規(guī)律的數(shù)字序列,需要的可以參考下2024-03-03