Python中__new__與__init__方法的區別詳解

在python2.x中,從object繼承得來的類稱爲新式類(如class A(object))不從object繼承得來的類稱爲經典類(如class A())python

新式類跟經典類的差異主要是如下幾點:編程

  1. 新式類對象能夠直接經過__class__屬性獲取自身類型:type函數

  2. 繼承搜索的順序發生了改變,經典類多繼承時屬性搜索順序: 先深刻繼承樹左側,再返回,開始找右側(即深度優先搜索);新式類多繼承屬性搜索順序: 先水平搜索,而後再向上移動code

例子:對象

經典類: 搜索順序是(D,B,A,C)繼承

>>> class A: attr = 1
...
>>> class B(A): pass
...
>>> class C(A): attr = 2
...
>>> class D(B,C): pass
...
>>> x = D()
>>> x.attr
1


新式類繼承搜索程序是寬度優先get

新式類:搜索順序是(D,B,C,A)it

>>> class A(object): attr = 1
...
>>> class B(A): pass
...
>>> class C(A): attr = 2
...
>>> class D(B,C): pass
...
>>> x = D()
>>> x.attr
2

  3. 新式類增長了__slots__內置屬性, 能夠把實例屬性的種類鎖定到__slots__規定的範圍之中。class

  4. 新式類增長了__getattribute__方法object

  5.新式類內置有__new__方法而經典類沒有__new__方法而只有__init__方法

注意:Python 2.x中默認都是經典類,只有顯式繼承了object纔是新式類

     而Python 3.x中默認都是新式類(也即object類默認是全部類的祖先),沒必要顯式的繼承object(能夠按照經典類的定義方式寫一個經典類並分別在python2.x和3.x版本中使用dir函數檢驗下。

例如:

class A():
    pass
 
print(dir(A))


會發如今2.x下沒有__new__方法而3.x下有。

接下來講下__new__方法和__init__的區別:

在python中建立類的一個實例時,若是該類具備__new__方法,會先調用__new__方法,__new__方法接受當前正在實例化的類做爲第一個參數(這個參數的類型是type,這個類型在c和python的交互編程中具備重要的角色,感興趣的能夠搜下相關的資料),其返回值是本次建立產生的實例,也就是咱們熟知的__init__方法中的第一個參數self。那麼就會有一個問題,這個實例怎麼獲得?

注意到有__new__方法的都是object類的後代,所以若是咱們本身想要改寫__new__方法(注意不改寫時在建立實例的時候使用的是父類的__new__方法,若是父類沒有則繼續上溯)能夠經過調用object的__new__方法類獲得這個實例(這實際上也和python中的默認機制基本一致),如:

class display(object):
  def __init__(self, *args, **kwargs):
    print("init")
  def __new__(cls, *args, **kwargs):
    print("new")
    print(type(cls))
    return object.__new__(cls, *args, **kwargs)  
a=display()

運行上述代碼會獲得以下輸出:

new
 
<class 'type'>
 
init

所以咱們能夠獲得以下結論:

在實例建立過程當中__new__方法先於__init__方法被調用,它的第一個參數類型爲type。

若是不須要其它特殊的處理,可使用object的__new__方法來獲得建立的實例(也即self)。

因而咱們能夠發現,實際上可使用其它類的__new__方法類獲得這個實例,只要那個類或其父類或祖先有__new__方法。

class another(object):
  def __new__(cls,*args,**kwargs):
    print("newano")
    return object.__new__(cls, *args, **kwargs)  
class display(object):
  def __init__(self, *args, **kwargs):
    print("init")
  def __new__(cls, *args, **kwargs):
    print("newdis")
    print(type(cls))
    return another.__new__(cls, *args, **kwargs)  
a=display()

上面的輸出是:

newdis
<class 'type'>
newano
init

全部咱們發現__new__和__init__就像這麼一個關係,__new__提供生產的原料self(但並不保證這個原料來源正宗,像上面那樣它用的是另外一個不相關的類的__new__方法類獲得這個實例),而__init__就用__new__給的原料來完善這個對象(儘管它不知道這些原料是否是正宗的)

相關文章
相關標籤/搜索