本文的目的是討論Python中 __new__ 和 __ini___ 的用法。 __new__ 和 __init__ 的區別主要表現在:1. 它自身的區別;2. 及在Python中新式類和老式類的定義。
理解 __new__ 和 __init__ 的區別
這兩個方法的主要區別在于:__new__ 負責對象的創建而 __init__ 負責對象的初始化。在對象的實例化過程中,這兩個方法會有些細微的差別,表現于:如何工作,何時定義。
Python中兩種類的定義方式
Python 2.x 中類的定義分為新式定義和老式定義兩種。老式的類出現在Python 3之前且定義時不繼承自'object' 基類,默認是繼承自'type' :而新式類在定義時顯示地繼承'object'類。
Python 2.x中老式類的定義:
class A: # -> inherits from type pass
Python 2.x中新式類的定義:
class A(object): # -> clearly inherits from object pass
在Python 3.x中沒有新式類和老式類之分,它們都繼承自'object' 類。因此可以不用顯示地指定其基類。'object'基類中擁有的方法和屬性可通用于所有的新式類。
下文中我們將通過測試 __new__ 和 __init__ 在各個case中的用法,來逐步剖析它們的功能和區別,并以此確實我們該如何使用它們。
分析不同的Case
在研究具體的實現之前,我們應該知道 __new__ 方法只接受 cls 作為它的第一個參數,而 __init__ 一個參數是 self (__new__ 是一個類方法,而__init__ 是一個對象方法)。因為我們調用 __new__ 之前連實例都還沒有,因此那時根本沒有 self 的存在。__init__ 在 使用 __new__ 創建并返回一個實例之后調用,因此可將返回的實例通過self傳遞給它。
老式類中的__new__ 和 __init__
老式類中其實并沒有 __new__ 方法,因為 __init__ 就是它的構造方法(函數)。因此如果我們有下面這段代碼:
class A:
def __new__(cls): print "A.__new__ is called" # -> this is never called
A()
這個case中的 __new__ 方法將永遠不會執行,因為它不是老式類的目標函數。
如果我們是重寫一個__init__ 方法:
class A:
def __init__(self): print "A.__init__ called"
A()
它將會輸出:
A.__init__ called
我們嘗試從 __init__ 方法中返回一個值:
class A:
def __init__(self): return 29
A()
將會產生一個錯誤:
TypeError: __init__() should return None?
這意味著我們實例化一個老式類的對象時,不能控制它返回什么內容。
新式類中的 __new__ 和 __init__
新式類允許開發者根據他們的意圖來重寫 __new__ 和 __init__ 方法。__new__ (構造函數)單獨地創建一個對象,而 __init__ (初始化函數)負責初始化這個對象。
我們看一下下面這個case的執行順序:
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()
將會輸出:
A.__new__ called
A.__init__ called
你可能想要問 __init__ 和 __new__ 是在哪里被調用的,我能告訴你的是: __new__ 是在我們調用類名進行實例化時自動調用的,__init__ 是在這個類的每一次實例化對象之后調用的,__new__ 方法創建一個實例之后返回這個實例對象并傳遞給 __init__ 方法的 self 參數。因此,即使你將創建的實例對象保存成一個全局或靜態的變量,并且每次調用__new__ 方法時都返回這個對象,__init__ 方法依然每次都會被調用。這意味著如果我們在 __new__ 中省略調用基類的super(A, cls).__new__(cls) 代碼,__init__ 方法將不會被執行。我們一起看一下這個case的代碼:
class A(object):
def __new__(cls): print "A.__new__ called" def __init__(self): print "A.__init__ called" # -> is actually never called print A()
輸出的內容如下:
A.__new__ called
None
Obviously the instantiation is evaluated to None since we don't return anything from the constructor.
顯然這個實例被認定None,如果我們沒有在構造函數中返回任何對象。
想像一下,如果我們從 __new__ 中返回一些其他東西(對象)將會發生什么,如下面這樣:
class A(object):
def __new__(cls): print "A.__new__ called" return 29
print A()
猜想會輸出如下的內容:
A.__new__ called
29
我們再看一下從 __init__ 中返回一個對象將會發生什么:
class A(object):
def __init__(self): print "A.__init__ called" return 33 # -> TypeError: __init__ should return None
A()
這將會出現警告:
TypeError: __init__ should return None
在調用 __init__ 時會出現一個TypeError的異常
:__init__() should return None, not ‘int'
。這主要是因為 __init__ 的作用只是刷新和更改剛創建的這個實例對象的狀態。
新式的類在靈活性上提供了更多的功能,允許我們在構造和初始化的級別做更多預處理和后處理的操作,讓我們可以在實例化時控制我們想要返回的內容。
考慮到這一點,我們嘗試一下在 __new__ 中返回一個其他類的對象。
首先,我們定義一個待用的類:
class Sample(object):
def __str__(self): return "SAMPLE"
然后,再定義一個重寫 __new__ 方法的類:
class A(object):
def __new__(cls): return Sample()
也可以寫成下面這樣:
class A(object):
def __new__(cls): return super(A, cls).__new__(Sample)
最后,我們調用A()來創建一個對象,并打印該對象:
print A()
這將會輸出:
SAMPLE
總結
以上所述是小編給大家介紹的Python中的 __new__ 和 __init__及區別介紹,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
