1. 程式人生 > >python3:__new__和__init__魔法函式區別

python3:__new__和__init__魔法函式區別

這兩個魔法函式是最容易混淆,面試官也經常會問到的知識點。咱們掌握區別以及原理,
就可以自信說:來呀,我不怕.

class  User:
    def __new__(cls, *args, **kwargs):
        print("new")

    def __init__(self,name):
        self.name=name
        print("init")

user=User()

列印結果:

new

通過上邊你可以發現兩個問題.
1.第一沒有傳引數居然沒有報錯.
2.沒有打印出 init 這句話.

解答下
1.new的功能是在生成物件之前所做的動作,接受的引數是cls 類


2.init是在物件生成之後完善物件的屬性 它接受的是self 物件
3.物件生成是在 new 裡面 return (返回一個物件)

我們用程式碼解釋這個三點,

new的功能是在生成物件之前所做的動作.

class  User:
    def __new__(cls, *args, **kwargs):
        print("new")

    def __init__(self,name):
        self.name=name
        print("init")

print(type(User("body")))

列印結果:

new
<class 'NoneType'>   # 					

雖然我們用 User(“body”))例項化了但是列印結果為none type ,根本不是一個物件.
原因是我們在 new 沒有返回任何物件. 故稱為在例項化物件之前的動作.
物件生成是在 new 裡面 return (返回一個物件)

我們在 new 返回一個物件,並列印物件type 是不是咱們預期的結果

class  User:
    def __new__(cls, *args, **kwargs):
        print("new")
        return super().__new__(cls)
    
print(type(User("body")))

pass

列印結果;

new
<class '__main__.User'>

我們呼叫了 父類的返回物件的方法return. 正如咱們所料 真的可以生成了物件.

有了物件以後 init 該幹活了.

.init是在物件生成之後完善物件的屬性

class  User:
    def __new__(cls, *args, **kwargs):
        print("new")
        return super().__new__(cls)

    def __init__(self,name):
        self.name=name
        print("init")

print(type(User("body")))

pass

列印結果:

new
init
<class '__main__.User'>

init這個方法,只要有物件立馬就執行.它執行的步驟是:
1.new 有兩個型別的引數*args, **kwargs ,這個兩引數如何用,我已經在getattr已經介紹
不懂得可以翻翻 , args 接受tupe, kwargs 接受 dict ,例如:User(“body”,name=“andy”)
new方法會儲存傳入引數在 物件裡.
看下程式碼:

    args = {tuple} <class 'tuple'>: ('body',)
    kwargs = {dict} {'name': 'andy'}

2.當遇到 init的時候會 把儲存資料 傳入 init並儲存在屬性裡. 順序不能變哦
3.當new 儲存的資料,加入 intit 沒有定義任何屬性,會報錯的,自己可以試試
說明 我物件有這些資料 ,你init 居然不完善這些屬性,我死給你看. 哈哈

它的用處是在元類程式設計裡大量的使用,以後講自定義元類也有這部分涉及,

但是絕大部分是不需要重寫new 這個函式.