目錄python
曾經我幼稚的覺得認識了python的__init__()方法就至關於認識了類構造器,結果,__new__()方法忽然出如今我眼前,讓我忽然認識到原來__new__纔是老大。爲何這麼說呢?spa
咱們首先得從__new__(cls[,...])的參數說提及,__new__方法的第一個參數是這個類,而其他的參數會在調用成功後所有傳遞給__init__方法初始化,這一會兒就看出了誰是老子誰是小子的關係。code
因此,__new__方法(第一個執行)先於__init__方法執行:對象
class A: pass class B(A): def __new__(cls): print("__new__方法被執行") return super().__new__(cls) def __init__(self): print("__init__方法被執行") b = B()
__new__方法被執行 __init__方法被執行
咱們比較兩個方法的參數,能夠發現__new__方法是傳入類(cls),而__init__方法傳入類的實例化對象(self),而有意思的是,__new__方法返回的值就是一個實例化對象(ps:若是__new__方法返回None,則__init__方法不會被執行,而且返回值只能調用父類中的__new__方法,而不能調用毫無關係的類的__new__方法)。咱們能夠這麼理解它們之間的關係,__new__是開闢疆域的大將軍,而__init__是在這片疆域上辛勤勞做的小老百姓,只有__new__執行完後,開闢好疆域後,__init__才能工做。繼承
絕大多數狀況下,咱們都不須要本身重寫__new__方法,但在當繼承一個不可變的類型(例如str類,int類等)時,它的特性就尤顯重要了。咱們舉下面這個例子:字符串
class CapStr(str): def __init__(self, string): string = string.upper() a = CapStr("I love China!") print(a)
I love China!
class CapStr(str): def __new__(cls, string): string = string.upper() return super().__new__(cls, string) a = CapStr("I love China!") print(a)
I LOVE CHINA!
咱們能夠根據上面的理論能夠這樣分析,咱們知道字符串是不可改變的,因此第一個例子中,傳入的字符串至關於已經被打下的疆域,而這塊疆域除了將軍其餘誰也沒法改變,__init__只能在這塊領地上乾瞪眼,此時這塊疆域就是」I love China!「。而第二個例子中,__new__大將軍從新去開闢了一塊疆域,因此疆域上的內容也發生了變化,此時這塊疆域變成了」I LOVE CHINA!「。string
小結:__new__和__init__想配合纔是python中真正的類構造器。it