__new()__ 與 __init()__的區別

Petrus_shuai發表於2018-09-08
class Student():
    # def  __call__(self, *args, **kwargs):
    #     obj=self.__new__(self)
    #     self.__init__(obj,*args, **kwargs)
    #     return obj

    def __new__(cls, *args, **kwargs):
        print(cls)
        print("__call__ is called")
        return object.__new__(cls)

    def __init__(self,name,age):
        print("__init__ is called")
        self.name=name
        self.age=age


    def __str__(self):
        return "the age of student[%s] is %s" %(self.name,self.age)
if __name__ == '__main__':
    t1=Student("zs",18)
    print(Student.mro())
    print(t1)
"""
<class '__main__.Student'>
__call__ is called
__init__ is called
[<class '__main__.Student'>, <class 'object'>]
the age of student[zs] is 18
"""

其中,__new__()不是一定要有,只有繼承自object的類才有,該方法可以return父類(通過super(當前類名, cls).__new__())出來的例項,或者直接是object的__new__出來的例項。值得注意的是,在定義子類時沒有重新定義__new__()時,Python預設呼叫該類父類的__new__()方法來構造該類例項,如果該類父類也沒有重寫__new__(),那麼將一直追溯至object的__new__()方法,因為object是所有新式類的基類。如果子類中重寫了__new__()方法,那麼可以自由選擇任意一個其他的新式類。

  可見,當類中同時出現__new__()和__init__()時,先呼叫__new__(),再呼叫__init__(),具體的執行過程為:

  1. 呼叫例項物件程式碼xiaoming = Student('xiaoming',175);

   2. 傳入name和height的引數,執行Student類的__new__()方法,該方法返回一個類的例項,通常會用父類super(Student,cls).__new__(cls),__new__()產生的例項即__init__()的self;

  3. 用例項來呼叫__init__()方法,進行初始化例項物件的操作。可以看到,python中__new__()與__init__()的區別,

  1.首先用法不同,__new__()用於建立例項,所以該方法是在例項建立之前被呼叫,它是類級別的方法,是個靜態方法;而 __init__() 用於初始化例項,所以該方法是在例項物件建立後被呼叫,它是例項級別的方法,用於設定物件屬性的一些初始值。由此可知,__new__()在__init__() 之前被呼叫。如果__new__() 建立的是當前類的例項,會自動呼叫__init__()函式,通過return呼叫的__new__()的引數cls來保證是當前類例項,如果是其他類的類名,那麼建立返回的是其他類例項,就不會呼叫當前類的__init__()函式。

  2.其次傳入引數不同:

  __new__()至少有一個引數cls,代表當前類,此引數在例項化時由Python直譯器自動識別;

  __init__()至少有一個引數self,就是這個__new__()返回的例項,__init__()在__new__()的基礎上完成一些初始化的操作。

        3.返回值不同:

  __new__()必須有返回值,返回例項物件;

  __init__()不需要返回值。

相關文章