Python對象生成
本篇文章轉載自網路。
new()是在新式類中新出現的方法,它作用在構造方法init()建造實例之前,可以這麼理解,在Python 中存在於類裡面的構造方法init()負責將類的實例化,而在init()調用之前,new()決定是否要使用該init()方法,因為new()可以調用其他類的構造方法或者直接返回別的對象來作為本類 的實例。 如果將類比喻為工廠,那麼init()方法則是該工廠的生產工人,init()方法接受的初始化參 數則是生產所需原料,init()方法會按照方法中的語句負責將原料加工成實例以供工廠出貨。而 new()則是生產部經理,new()方法可以決定是否將原料提供給該生產部工人,同時它還決定著出 貨產品是否為該生產部的產品,因為這名經理可以借該工廠的名義向客戶出售完全不是該工廠的產品。 new()方法的特性: new()方法是在類準備將自身實例化時調用。 new()方法始終都是類的靜態方法,即使沒有被加上靜態方法裝飾器。
類的實例化和它的構造方法通常都是這個樣子:
class MyClass(object): def __init__(self, *args, **kwargs): ...# 實例化myclass = MyClass(*args, **kwargs)
正如以上所示,一個類可以有多個位置參數和多個命名參數,而在實例化開始之後,在調用 init()方法之前,Python首先調用new()方法:
def __new__(cls, *args, **kwargs): ...
第一個參數cls是當前正在實例化的類。 如果要得到當前類的實例,應當在當前類中的new()方法語句中調用當前類的父類 的new()方法。 例如,如果當前類是直接繼承自object,那當前類的new()方法返回的對象應該為:
def __new__(cls, *args, **kwargs): ... return object.__new__(cls)
事實上如果(新式)類中沒有重寫new()方法,即在定義新式類時沒有重新定義new()時 ,Python默認是調用該類的直接父類的new()方法來構造該類的實例,如果該類的父類也沒有重寫 new(),那麼將一直按此規矩追溯至object的new()方法,因為object是所有新式類的基類。 而如果新式類中重寫了new()方法,那麼你可以自由選擇任意一個的其他的新式類(必定要是 新式類,只有新式類必定都有new(),因為所有新式類都是object的後代,而經典類則沒有new() 方法)的new()方法來製造實例,包括這個新式類的所有前代類和後代類,只要它們不會造成遞歸死 循環。具體看以下代碼解釋:
class Foo(object): def __init__(self, *args, **kwargs): ... def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) # 以上return等同於 # return object.__new__(Foo, *args, **kwargs)# return Stranger.__new__(cls, *args, **kwargs)# return Child.__new__(cls, *args, **kwargs)class Child(Foo): def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs)
#如果Child中沒有定義new()方法,那麼會自動調用其父類的new()方法來製造實例,即
Foo.__new__(cls, *args, **kwargs)
在任何新式類的new()方法,不能調用自身的new()來製造實例,因為這會造成死循環。因此必須避免類似以下的寫法: 在Foo中避免:return Foo.new(cls, *args, **kwargs)或return cls.new(cls, *args, **kwargs)。
使用object或者沒有血緣關係的新式類的new()是安全的,但是如果是在有繼承關係的兩個類之間,應避免互調造成死循環,例如:(Foo)return Child.new(cls), (Child)return Foo.new(cls)。
class Stranger(object): ...
在製造Stranger實例時,會自動調用 object.new(cls) 通常來說,新式類開始實例化時,new()方法會返回cls(cls指代當前類)的實例,然後該類的 init()方法作為構造方法會接收這個實例(即self)作為自己的第一個參數,然後依次傳入new ()方法中接收的位置參數和命名參數。
注意:如果new()沒有返回cls(即當前類)的實例,那麼當前類的init()方法是不會被調用 的。如果new()返回其他類(新式類或經典類均可)的實例,那麼只會調用被返回的那個類的構造方 法。
class Foo(object): def __init__(self, *args, **kwargs): ... def __new__(cls, *args, **kwargs): return object.__new__(Stranger, *args, **kwargs) class Stranger(object): ...foo = Foo()print type(foo)
列印的結果顯示foo其實是Stranger類的實例。
因此可以這麼描述new()和ini()的區別,在新式類中new()才是真正的實例化方法,為類提供外殼製造出實例框架,然後調用該框架內的構造方法init()使其豐滿。 如果以建房子做比喻,new()方法負責開發地皮,打下地基,並將原料存放在工地。而init()方法負責從工地取材料建造出地皮開發招標書中規定的大樓,init()負責大樓的細節設計,建造,裝修使其可交付給客戶。
推薦閱讀:
※第一節課:安裝python
※Pythonic之道——個人總結
※word文檔(docx)的讀取和寫入:docx模塊
※Numpy庫學習
TAG:Python |