__new__()
是在新式類中新出現(xiàn)的方法,它作用在構(gòu)造方法( __init__()
)建造實(shí)例之前. 可以這么理解,在 Python 中存在于類里面的構(gòu)造方法 __init__()
負(fù)責(zé)將類進(jìn)行實(shí)例化,而在 __init__()
啟動之前,__new__()
決定是否要使用該 __init__()
方法,因?yàn)?__new__()
也可以調(diào)用其他類的構(gòu)造方法或者直接返回別的對象來作為本類的實(shí)例。
如果將類比喻為工廠,那么 __init__()
方法則是該工廠的生產(chǎn)工人,__init__()
方法接受的初始化參數(shù)則是生產(chǎn)所需原料,__init__()
方法會按照方法中的語句負(fù)責(zé)將原料加工成實(shí)例以供工廠出貨。而 __new__()
則是生產(chǎn)部經(jīng)理,__new__()
方法可以決定是否將原料提供給該生產(chǎn)部工人,同時它還決定著出貨產(chǎn)品是否為該生產(chǎn)部的產(chǎn)品,因?yàn)檫@名經(jīng)理可以借該工廠的名義向客戶出售完全不是該工廠的產(chǎn)品。
__new__()
方法的特性:
-
__new__()
方法是在類準(zhǔn)備將自身實(shí)例化時調(diào)用。 -
__new__()
方法始終都是類的靜態(tài)方法,即使沒有被加上靜態(tài)方法裝飾器。
類的實(shí)例化和構(gòu)造方法通常是這個樣子:
class MyClass(object):
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
...
# 實(shí)例化
myclass = MyClass(*args, **kwargs)
正如以上代碼所示,一個類可以有多個位置參數(shù)和多個命名參數(shù),而在實(shí)例化開始之后,在調(diào)用 __init__()
方法之前,Python 首先調(diào)用 __new__()
方法.
__new__
的參數(shù)解釋:
-
cls
表示當(dāng)前類. -
*args
和**kwargs
分別表示該類進(jìn)行初始化時, 輸入的位置參數(shù)和命名參數(shù)。
__new__
函數(shù)一般會有返回語句, 在返回語句中:object.__new__()
表示調(diào)用object
類的__new__()
函數(shù), 也可以使用super().__new__()
, 表示調(diào)用當(dāng)前類的父類的__new__()
, 如果父類沒有自定義__new__()
, 就會調(diào)用該父類的父類的__new__()
, 以此類推, 直到object
類.return
中的__new__()
函數(shù)的第一個參數(shù)cls
表示將要返回的類的類型,cls
表示用于返回當(dāng)前類, 也可以返回其他類.
事實(shí)上如果(新式)類中沒有重寫 __new__()
方法,即在定義新式類時沒有重新定義 __new__()
時,Python 默認(rèn)是調(diào)用該類的直接父類的 __new__()
方法來構(gòu)造該類的實(shí)例,如果該類的父類也沒有重寫 __new__()
,那么將一直按此規(guī)則追溯至 object
類的 __new__()
方法,因?yàn)?object
類是所有新式類的基類。
如果新式類中重寫了 __new__()
方法,那么你可以自由選擇任意一個的其他的新式類(必定要是新式類,只有新式類必定都有 __new__()
,因?yàn)樗行率筋惗际?object
的后代,而經(jīng)典類則沒有 __new__()
方法)的 __new__()
方法來制造實(shí)例,包括這個新式類的所有前代類和后代類,只要它們不會造成遞歸死循環(huán)。具體看以下代碼解釋:
class Foo(object):
def __init__(self, *args, **kwargs):
...
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
class Child(Foo):
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
class Stranger(object):
def __new__(cls, *args, **kwargs):
...
- 如果Child中沒有定義
__new__()
方法,那么會自動調(diào)用其父類的__new__()
方法來制造實(shí)例,即Foo.__new__(cls, *args, **kwargs)
。 - 在任何新式類的
__new__()
方法,不能調(diào)用自身的__new__()
來制造實(shí)例,因?yàn)檫@會造成死循環(huán)。因此必須避免類似以下的寫法:
- 在
Foo
中避免:return Foo.__new__(cls, *args, **kwargs)
或return cls.__new__(cls, *args, **kwargs)
。Child
同理。 - 使用
object
或者沒有血緣關(guān)系的新式類的__new__()
是安全的,但是如果是在有繼承關(guān)系的兩個類之間,應(yīng)避免互調(diào)造成死循環(huán),例如:(Foo) return Child.__new__(cls)
,(Child) return Foo.__new__(cls)
。
- 在制造
Stranger
實(shí)例時,會自動調(diào)用object.__new__(cls)
.
通常來說,新式類開始實(shí)例化時,__new__()
方法會返回 cls
( cls
指代當(dāng)前類)的實(shí)例,然后該類的 __init__()
方法作為構(gòu)造方法會接收這個實(shí)例(即self
)作為自己的第一個參數(shù),然后依次傳入 __new__()
方法中接收的位置參數(shù)和命名參數(shù)。
__new__()
除了返回 cls
(當(dāng)前類) 的實(shí)例之外,還可以有其他用法:
- 返回其他類:
class Foo(object):
def __new__(cls, *args, **kwargs):
return object.__new__(Stranger, *args, **kwargs)
def __init__(self, *args, **kwargs):
...
class Stranger(object):
...
foo = Foo()
print(type(foo))
打印的結(jié)果顯示 foo
其實(shí)是 Stranger
類的實(shí)例。
- 返回其他數(shù)據(jù)類型:
a = 10
class Foo(object):
def __new__(cls, *args, **kwargs):
print("__new__ is called.")
return a
def __init__(self, *args, **kwargs):
...
Foo()
執(zhí)行結(jié)果為:
__new__ is called
10
可以這么描述 __new__()
和 __ini__()
的區(qū)別,在新式類中 __new__()
才是真正的實(shí)例化方法,為類提供外殼制造出實(shí)例框架,然后調(diào)用該框架內(nèi)的構(gòu)造方法 __init__()
使其豐滿。
如果以建房子做比喻,__new__()
方法負(fù)責(zé)開發(fā)地皮,打下地基,并將原料存放在工地。而 __init__()
方法負(fù)責(zé)從工地取材料建造出地皮開發(fā)招標(biāo)書中規(guī)定的大樓,__init__()
負(fù)責(zé)大樓的細(xì)節(jié)設(shè)計,建造,裝修使其可交付給客戶。
注意:如果 __new__()
沒有返回 cls
(即當(dāng)前類)的實(shí)例,那么當(dāng)前類的 __init__()
方法是不會被調(diào)用的。如果 __new__()
返回其他類(新式類或經(jīng)典類均可)的實(shí)例,那么只會調(diào)用被返回的那個類的構(gòu)造方法。