說說Python中的__new__和__init__的區別?

2021-02-19 程序IT圈

公眾號新增加了一個欄目,就是每天給大家解答一道Python常見的面試題,反正每天不貪多,一天一題,正好合適,只希望這個面試欄目,給那些正在準備面試的同學,提供一點點幫助!

小猿會從最基礎的面試題開始,每天一題。如果參考答案不夠好,或者有錯誤的話,麻煩大家可以在留言區給出自己的意見和討論,大家是要一起學習的 。

廢話不多說,開始今天的題目:

問:說說Python中的__new__和__init__的區別?

答:在Python中__new__和__init__具有不同的功能。並且對於Python的新類和舊類而言功能也不同。

__new__是在實例創建之前被調用的,因為它的任務就是創建實例然後返回該實例對象,是個靜態方法。

__init__是當實例對象創建完成後被調用的,然後設置對象屬性的一些初始值,通常用在初始化一個類實例的時候。是一個實例方法。

主要區別在於:__new__是用來創造一個類的實例的,而__init__是用來初始化一個實例的。

下文來源於:

https://www.jianshu.com/p/14b8ebf93b73

Python的新類和舊類

Python中的類分為新類和舊類。舊類是Python3之前的類,舊類並不是默認繼承object類,而是繼承type類。

Python2中的舊類如下面代碼所示:

class oldStyleClass:
pass

Python2中定義一個新類:

class newStyleClass(object):
pass

在Python3中所有的類均默認繼承object,所以並不需要顯式地指定object為基類。

以object為基類可以使得所定義的類具有新類所對應的方法(methods)和屬性(properties)。

在下面的文章中我們會分別基於新類和舊類探討__new__和__init__。

__new__和__init__參數的不同

__new__所接收的第一個參數是cls,而__init__所接收的第一個參數是self。這是因為當我們調用__new__的時候,該類的實例還並不存在(也就是self所引用的對象還不存在),所以需要接收一個類作為參數,從而產生一個實例。而當我們調用__init__的時候,實例已經存在,因此__init__接受self作為第一個參數並對該實例進行必要的初始化操作。這也意味著__init__是在__new__之後被調用的。

Python舊類中的__new__和__init__

Python的舊類中實際上並沒有__new__方法。因為舊類中的__init__實際上起構造器的作用。所以如果我們定義如下舊類:

class oldStyleClass:
def __new__(cls):
print("__new__ is called")

oldStyleClass()

程序輸出結果如下:

<__main__.oldStyleClass instance at 0x109c45518>

可見創建及初始化對象的過程並沒有調用__new__。實際上,除非顯式調用:oldStyleClass.__new__(oldStyleClass),該類中的__new__方法中的內容永遠不會被調用。因為舊類構造實例並不會調用__new__方法。

但如果我們重載__init__方法:

class oldStyleClass:
def __init__(self):
print("__init__ is called")

oldStyleClass()

該程序將會輸出

__init__ is called
<__main__.oldStyleClass instance at 0x1091992d8>

如果我們在__init__中加上return語句,將會導致TypeError: __init__() should return None的錯誤。

class oldStyleClass:
def __init__(self):
return 29

oldStyleClass()

程序結果如下:

TypeError: __init__() should return None

這意味著對於Python的舊類而言,我們無法控制__init__函數的返回值。

Python新類中的__new__和__init__

Python的新類允許用戶重載__new__和__init__方法,且這兩個方法具有不同的作用。__new__作為構造器,起創建一個類實例的作用。而__init__作為初始化器,起初始化一個已被創建的實例的作用。

如下面代碼是所示:

class newStyleClass(object):



def __new__(cls):
print("__new__ is called")
return super(newStyleClass, cls).__new__(cls)

def __init__(self):
print("__init__ is called")
print("self is: ", self)

newStyleClass()

結果如下:

__new__ is called
__init__ is called
self is: <__main__.newStyleClass at 0x109290890>
<__main__.newStyleClass at 0x109290890>

創建類實例並初始化的過程中__new__和__init__被調用的順序也能從上面代碼的輸出結果中看出:__new__函數首先被調用,構造了一個newStyleClass的實例,接著__init__函數在__new__函數返回一個實例的時候被調用,並且這個實例作為self參數被傳入了__init__函數。

這裡需要注意的是,如果__new__函數返回一個已經存在的實例(不論是哪個類的),__init__不會被調用。如下面代碼所示:

obj = 12


class returnExistedObj(object):
def __new__(cls):
print("__new__ is called")
return obj

def __init(self):
print("__init__ is called")

returnExistedObj()

執行結果如下:

__new__ is called
12

同時另一個需要注意的點是:

如果我們在__new__函數中不返回任何對象,則__init__函數也不會被調用。

如下面代碼所示:

class notReturnObj(object):
def __new__(cls):
print("__new__ is called")

def __init__(self):
print("__init__ is called")

print(notReturnObj())

執行結果如下:

__new__ is called
None

可見如果__new__函數不返回對象的話,不會有任何對象被創建,__init__函數也不會被調用來初始化對象。

總結幾個點

__init__不能有返回值

__new__函數直接上可以返回別的類的實例。如上面例子中的returnExistedObj類的__new__函數返回了一個int值。

只有在__new__返回一個新創建屬於該類的實例時當前類的__init__才會被調用。如下面例子所示:

class sample(object):
def __str__(self):
print("sample")

class example(object):
def __new__(cls):
print("__new__ is called")
return sample()

def __init__(self):
print("__init__ is called")

example()

輸出結果為:

__new__ is called
sample

如果對於參考答案有不認同的,大家可以在評論區指出和補充,歡迎留言!

10、說說Python可變與不可變數據類型?

11、說說Python模塊主要分哪三類?

12、列舉Python中的標準異常類?

13、Python中深拷貝與淺拷貝的區別?

14、Python中迭代器和生成器的區別?

15、Python可迭代對象怎麼獲取迭代器?

16、你了解什麼是 Python 之禪麼?

17、說說Python字典以及基本操作?

18、說說Python有幾種字符串格式化?

19、說說Python多線程與多進程的區別?

20、說說HTTP常見響應狀態碼?

21、Python 單引號、雙引號、三引號區別?

22、說說Python中猴子補丁是什麼?

23、說說Python中的垃圾回收機制?

24、Python中有幾種交換兩個變量的值?

25、說說Python中的6種位運算符?

26、說說Python中的類型轉換有哪些?

27、Python中實現二分查找的2種方法?

28、說說Python中的lambda表達式?

29、說說Python中的反射是什麼?

30、Python刪除list的重複元素有幾種方法?

關注小猿公眾號,每天學習一道題

相關焦點

  • 詳解Python中的__init__和__new__的區別
    當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最先被調用的方法 其實是 __new__ 方法。二、__new__ 方法是什麼?__new__方法接受的參數雖然也是和__init__一樣,但__init__是在類實例創建之後調用,而 __new__方法正是創建這個類實例的方法。
  • Python面試之理解__new__和__init__的區別
    中的__init__是構造方法,但其實不然,Python中真正的構造方法是__new__。__init__和__new__有什麼區別?本文就來探討一下。我們先來看一下__init__的用法class Person(object):    def __init__(self, name, age):        print("in __init__")        self.
  • python知識掃盲(1)-__init__與__new__的區別
    __new__中cls代表類,args為參數列表;__init__中self代表實例對象,args為參數列表。__new__方法是靜態方法,而__init__為實例方法。__new__方法一般返回類的對象,當返回類的對象時將會自動調用__init__方法進行初始化,如果沒有對象返回,則__init__方法不會被調用。
  • Python中__init__.py文件的作用詳解
    __init__.py 文件的作用是將文件夾變為一個Python模塊,Python 中的每個模塊的包中,都有__init__.py 文件。
  • 【Python面試】 說說Python中xrange和range的區別?
    如果參考答案不夠好,或者有錯誤的話,麻煩大家可以在留言區給出自己的意見和討論,大家是要一起學習的 。廢話不多說,開始今天的題目:問:說說Python中xrange和range的區別?答:range()和xrange()都是在循環中使用,輸出結果一樣。
  • Python小知識: __init__.py的作用
    __init__.py 文件的作用是將文件夾變為一個Python模塊,Python 中的每個模塊的包中,都有__init__.py 文件。通常__init__.py 文件為空,但是我們還可以為它增加其他的功能。我們在導入一個包時,實際上是導入了它的__init__.py文件。這樣我們可以在__init__.py文件中批量導入我們所需要的模塊,而不再需要一個一個的導入。
  • Python中 *args 和 **kwargs 的含義?
    如果參考答案不夠好,或者有錯誤的話,麻煩大家可以在留言區給出自己的意見和討論,大家是要一起學習的 。廢話不多說,開始今天的題目:問:Python中 *args 和 **kwargs 的含義?答:在python中,*args和**kwargs通常使用在函數定義裡。
  • Python 中常用的魔術方法
    博客地址:zhihu.com/people/zarten概述python中特殊方法(魔術方法)是被python解釋器調用的,我們自己不需要調用它們,我們統一使用內置函數來使用。而__init__()用來初始化實例,所以__new__()比__init___()先執行。
  • Python 2 與 Python 3 的區別
    最近的項目開始用Python3寫了,也體會了一下2和3的區別。xrangePython 2中有 range 和 xrange 兩個方法。其區別在於,range返回一個list,在被調用的時候即返回整個序列;xrange返回一個iterator,在每次循環中生成序列的下一個數字。Python 3中不再支持 xrange 方法,Python 3中的 range 方法就相當於 Python 2中的 xrange 方法。
  • Python和JAVA的區別
    區別:1.Python比Java簡單,學習成本低,開發效率高2.Java運行效率高於Python,尤其是純Python開發的程序,效率低3.Java相關資料多,尤其是中文資料一些細節區別:1.數python只有四種數據:整數,長整數、浮點數和複數 java則有char,short,byte,int,long,float,double類型2. 字符串2.1.
  • Python中最基礎的面試題,這你都不會,就不再說Python簡單了
    下列哪個表達式在Python中是非法的?Linux中線程的調度由作業系統控制D. Linux中協程的調度由作業系統控制13. 下列哪種函式參數定義不合法?__foo解析器用_classname__foo來代替這個名字,以區別和其他類相同的命名C. __foo__代表python裡特殊方法專用的標識D. __foo 可以直接用於』from module import *』25.
  • Python 中 staticmethod 和 classmethod 原理探究
    起步文章Python 中 property 的實現原理及實現中探究了 property 的實現原理。如果能理解那邊描述符的使用方式,那也能很快理解本篇中的 staticmethod 和 classmethod 。
  • 很全的 Python 面試題
    在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是可以修改的對象。15 __new__和__init__的區別這個__new__確實很少見到,先做了解吧.__new__是一個靜態方法,而__init__是一個實例方法.__new__方法會返回一個創建的實例,而__init__什麼都不返回.只有在__new__返回一個cls的實例時後面的__init__才能被調用.
  • Python中 __init__的通俗解釋
    前言作為典型的面向對象的語言,Python中 類 的定義和使用是不可或缺的一部分知識。
  • Python中模塊(Module)和包(Package)到底是什麼,有什麼區別?
    模塊(Module)在電腦程式的開發過程中,隨著程序代碼越寫越多,在一個文件裡代碼就會越來越長,越來越不容易維護。為了編寫可維護的代碼,我們把很多函數分組,分別放到不同的文件裡,這樣,每個文件包含的代碼就相對較少,很多程式語言都採用這種組織代碼的方式。在Python中,一個.py文件就稱之為一個模塊(Module)。
  • Python面試常見問題,__init__是構造函數嗎?
    你不假思索,當然是__init__啦!如果你這麼回答,很有可能你就和offer無緣了。因為在Python當中__init__並不是構造函數,__new__才是。是不是有點蒙,多西得(日語:為什麼)?我們不是一直將__init__方法當做構造函數來用的嗎?
  • 這8道Python面試題,你答不答的出來
    a[1].append(5)print (a)print (b)>>[1, [2, 3, 4, 5]]#因為是深度拷貝,改變了a[1],b[1]內容不會改變[1, [2, 3, 4]]Python中==和is的區別is是判讀對象標識符是否一致,而==是判讀兩個對象的內容是否相等!
  • Python中classmethod和staticmethod的區別
    今天來寫一下裝飾器classmethod和staticmethod這兩個關鍵詞。
  • 盤點Python編程中遇到的無數個「坑」(多繼承下__init__()方法)
    我們知道,Python面向對象編程中,在類創建完成後,一般使用__init__()方法對實例屬性進行初始化。但是,在使用__init__()方法進行變量初始化時,如果使用不當,也會有一些覺察不到的「坑」。
  • Python安裝教程和使用技巧
    具有可移植性,支持面向過程和面向對象編程,並且開源。window系統中,python有多種開發工具,例如1.直接在cmd命令窗口執行,但此種僅能單條語句執行,不能運行完整的程序。2.python自帶的集成開發環境,可通過開始——所有程序——python3.3——IDLE(Python GUI)啟動。