Python中的__new__和__init__的區(qū)別

摘要

本文討論了Python中__init____new__方法。

__new____init__具有不同的功能。并且對于Python的新類和舊類而言功能也不同。

__new____init__功能上的區(qū)別

__new____init__的主要區(qū)別在于:__new__是用來創(chuàng)造一個類的實例的(constructor),而__init__是用來初始化一個實例的(initializer)。

Python的新類和舊類

Python中的類分為新類和舊類。舊類是Python3之前的類,舊類并不是默認(rèn)繼承object類,而是繼承type類。

Python2中的舊類如下面代碼所示:

class oldStyleClass: # inherits from 'type'
    pass

Python2中定義一個新類:

class newStyleClass(object): # explicitly inherits from 'object'
    pass

在Python3中所有的類均默認(rèn)繼承object,所以并不需要顯式地指定object為基類。

object為基類可以使得所定義的類具有新類所對應(yīng)的方法(methods)和屬性(properties)。

在下面的文章中我們會分別基于新類和舊類探討__new____init__。

__new____init__參數(shù)的不同

__new__所接收的第一個參數(shù)是cls,而__init__所接收的第一個參數(shù)是self。這是因為當(dāng)我們調(diào)用__new__的時候,該類的實例還并不存在(也就是self所引用的對象還不存在),所以需要接收一個類作為參數(shù),從而產(chǎn)生一個實例。而當(dāng)我們調(diào)用__init__的時候,實例已經(jīng)存在,因此__init__接受self作為第一個參數(shù)并對該實例進行必要的初始化操作。這也意味著__init__是在__new__之后被調(diào)用的。

Python舊類中的__new____init__

Python的舊類中實際上并沒有__new__方法。因為舊類中的__init__實際上起構(gòu)造器的作用。所以如果我們定義如下舊類:

class oldStyleClass:
    def __new__(cls):
        print("__new__ is called") # this line will never get called during construction

oldStyleClass()

程序輸出結(jié)果如下:

<__main__.oldStyleClass instance at 0x109c45518>

可見創(chuàng)建及初始化對象的過程并沒有調(diào)用__new__。實際上,除非顯式調(diào)用:oldStyleClass.__new__(oldStyleClass),該類中的__new__方法中的內(nèi)容永遠(yuǎn)不會被調(diào)用。因為舊類構(gòu)造實例并不會調(diào)用__new__方法。

但如果我們重載__init__方法:

class oldStyleClass:
    def __init__(self):
        print("__init__ is called")

oldStyleClass()

該程序?qū)敵?/p>

__init__ is called
<__main__.oldStyleClass instance at 0x1091992d8>

如果我們在__init__中加上return語句,將會導(dǎo)致TypeError: __init__() should return None的錯誤。

class oldStyleClass:
    def __init__(self):
        return 29

oldStyleClass()

程序結(jié)果如下:

TypeError: __init__() should return None

這意味著對于Python的舊類而言,我們無法控制__init__函數(shù)的返回值。

Python新類中的__new____init__

Python的新類允許用戶重載__new____init__方法,且這兩個方法具有不同的作用。__new__作為構(gòu)造器,起創(chuàng)建一個類實例的作用。而__init__作為初始化器,起初始化一個已被創(chuàng)建的實例的作用。

如下面代碼是所示:

class newStyleClass(object): 
    # In Python2, we need to specify the object as the base.
    # In Python3 it's default.

    def __new__(cls):
        print("__new__ is called")
        return super(newStyleClass, cls).__new__(cls)

    def __init__(self):
        print("__init__ is called")
        print("self is: ", self)

newStyleClass()

結(jié)果如下:

__new__ is called
__init__ is called
self is: <__main__.newStyleClass at 0x109290890>
<__main__.newStyleClass at 0x109290890>

創(chuàng)建類實例并初始化的過程中__new____init__被調(diào)用的順序也能從上面代碼的輸出結(jié)果中看出:__new__函數(shù)首先被調(diào)用,構(gòu)造了一個newStyleClass的實例,接著__init__函數(shù)在__new__函數(shù)返回一個實例的時候被調(diào)用,并且這個實例作為self參數(shù)被傳入了__init__函數(shù)。

這里需要注意的是,如果__new__函數(shù)返回一個已經(jīng)存在的實例(不論是哪個類的),__init__不會被調(diào)用。如下面代碼所示:

obj = 12 
# obj can be an object from any class, even object.__new__(object)

class returnExistedObj(object):
    def __new__(cls):
        print("__new__ is called")
        return obj

    def __init(self):
        print("__init__ is called")

returnExistedObj()

執(zhí)行結(jié)果如下:

__new__ is called
12

同時另一個需要注意的點是:

如果我們在__new__函數(shù)中不返回任何對象,則__init__函數(shù)也不會被調(diào)用。

如下面代碼所示:

class notReturnObj(object):
    def __new__(cls):
        print("__new__ is called")

    def __init__(self):
        print("__init__ is called")

print(notReturnObj())

執(zhí)行結(jié)果如下:

__new__ is called
None

可見如果__new__函數(shù)不返回對象的話,不會有任何對象被創(chuàng)建,__init__函數(shù)也不會被調(diào)用來初始化對象。

總結(jié)幾個點

  1. __init__不能有返回值

  2. __new__函數(shù)直接上可以返回別的類的實例。如上面例子中的returnExistedObj類的__new__函數(shù)返回了一個int值。

  3. 只有在__new__返回一個新創(chuàng)建屬于該類的實例時當(dāng)前類的__init__才會被調(diào)用。如下面例子所示:

class sample(object):
    def __str__(self):
        print("sample")

class example(object):
    def __new__(cls):
        print("__new__ is called")
        return sample()

    def __init__(self):
        print("__init__ is called")

example()

輸出結(jié)果為:

__new__ is called
sample
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Python進階框架 希望大家喜歡,點贊哦首先感謝廖雪峰老師對于該課程的講解 一、函數(shù)式編程 1.1 函數(shù)式編程簡...
    Gaolex閱讀 5,979評論 6 53
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,633評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,527評論 19 139
  • python的函數(shù)參數(shù)傳遞 看兩個例子: 所有變量都可以理解為內(nèi)存中一個對象的“引用”,或者,可以看做C中的vio...
    marvinxu閱讀 6,021評論 2 30
  • 定義類并創(chuàng)建實例 在Python中,類通過 class 關(guān)鍵字定義。以 Person 為例,定義一個Person類...
    績重KF閱讀 4,096評論 0 13

友情鏈接更多精彩內(nèi)容