Python類的__new__()


 

  本篇主要想要詳細的介紹一下關於類的魔法方法__new__()方法。

  在學習之前我們看一下Python3中關於object基類的__new__() 方法:

    @staticmethod # known case of __new__
    def __new__(cls, *more): # known special case of object.__new__
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

  上述描述:__new__()創建和返回一個新的對象。通俗說:該魔法屬性是用來創建實例對象的。接下來我們看一下它的是如何創建對象的。

一、理解

  1、__new__()是在新式類中新出現的方法,它作用在構造方法建造實例之前。

  即可以這樣理解:Python中存在於類中的構造方法__init__()負責將類實例化,而在__init__()執行之前,__new__()負責制造這樣的一個實例對象,以便__init__()去讓該實例對象更加的豐富(為其添加屬性等)。

  同時:__new__() 方法還決定是否要使用該__init__() 方法,因為__new__()可以調用其他類的構造方法或者直接返回別的對象來作為本類 的實例。

  2、__new__() 方法始終都是類的靜態方法,即使沒有被加上靜態方法裝飾器。

    比喻

  

  如果將類比喻為工廠,那么__init__()方法則是該工廠的生產工人,__init__()方法接受的初始化參 數則是生產所需原料,__init__()方法會按照方法中的語句負責將原料加工成實例以供工廠出貨。而 __new__()則是生產部經理,__new__()方法可以決定是否將原料提供給該生產部工人,同時它還決定着出 貨產品是否為該生產部的產品,因為這名經理可以借該工廠的名義向客戶出售完全不是該工廠的產品。

  

二、結構

  在Python中,若不重寫類中的__new__()方法,其默認的結構時這樣的:

class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return super().__new__(cls,*args,**kwagrs)

  1、其第一個參數 cls 是當前正在實例化的類。 

  如果要得到當前類的實例,應當在當前類中的__new__()方法語句中調用當前類的父類 的__new__()方法。例如,如果當前類是直接繼承自object,那當前類的__new__()方法返回的對象應該為:
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)

  注:①、如果(新式)類中沒有重寫__new__()方法,即在定義新式類時沒有重新定義__new__()時 ,Python默認是調用該類的直接父類的__new__()方法來構造該類的實例,如果該類的父類也沒有重寫 __new__(),那么將一直按此規矩追溯至object的__new__()方法,因為object是所有新式類的基類。

  ②、如果新式類中重寫了__new__()方法,那么你可以自由選擇任意一個的其他的新式類(必定要是 新式類,只有新式類必定都有__new__(),因為所有新式類都是object的后代,而經典類則沒有__new__() 方法)的__new__()方法來制造實例,包括這個新式類的所有前代類和后代類,只要它們不會造成遞歸死 循環。

class A(object):
    pass

class B(A):
    pass

class C(B):
    def __new__(cls,*args,**kwargs):
        return super().__new__(cls, *args,**kwargs)

        # 等同於:
        # return B.__new__(cls, *args,**kwargs)
        # return A.__new__(cls, *args,**kwargs)
        # return object.__new__(cls, *args,**kwargs)

  2、在任何新式類的__new__()方法,不能調用自身的__new__()來制造實例,因為這會造成死循環。

  例如:

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return Bar.__new__(Foo,*agrs,**kwagrs)

  這樣的話會造成 當Bar調用其自身的__new__() 方法制造實例時,又會跳到第二行去執行__new__(),當到第三行時,又跳到第二行去調用__new__(),這樣不斷的就會陷入死循環。

  3、Bar.__new__(Foo,*agrs,**kwagrs) ,指:使用哪個類(bar)的__new__()方法去制造誰的(Foo)實例對象。

  通常來說,新式類開始實例化時,__new__()方法會返回cls(cls指代當前類)的實例,然后該類的 __init__()方法作為構造方法會接收這個實例(即self)作為自己的第一個參數,然后依次傳入__new__ ()方法中接收的位置參數和命名參數。

  注:如果__new__()沒有返回cls(即當前類)的實例,那么當前類的__init__()方法是不會被調用 的。如果__new__()返回其他類(新式類或經典類均可)的實例,那么只會調用被返回的那個類的構造方 法。
class Foo(object):
    def __new__(cls,*args,**kwagrs):
        return object.__new__(cls,*args,**kwagrs)
    
    def __init__(self,name):
        self.name = name

class Bar(object):
    def __new__(cls,*agrs,**kwagrs):
        return object.__new__(Foo,*agrs,**kwagrs)
    
bar = Bar()
print(type(bar)) #foo其實是Stranger類的實例。

# 輸出為:<class '__main__.Foo'>

   會發現上例:制造的是Foo的實例對象。

 

  總結:因此可以這么描述__new__()和__ini__()的區別,在新式類中__new__()才是真正的實例化方法,為類提供外殼制造出實例框架,然后調用該框架內的構造方法__init__()使其豐滿。

    如果以建房子做比喻,__new__()方法負責開發地皮,打下地基,並將原料存放在工地。而__init__()方法負責從工地取材料建造出地皮開發招標書中規定的大樓,__init__()負責大樓的細節設計,建造,裝修使其可交付給客戶。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM