python新式類和經典類的區別



1,新式類和經典類的區別:
廣度優先和深度優先,這主要是在多類繼承的時候會使用到,如下多類繼承的D類對比:
經典類在加載的時候采用的是深度優先算法,二新式類采用的是廣度優先算法:比如
經典類: 搜索順序是(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

新式類繼承搜索程序是寬度優先
新式類:搜索順序是(D,B,C,A)
>>> class A(object): attr = 1
...
>>> class B(A): pass
...
>>> class C(A): attr = 2
...
>>> class D(B,C): pass
...
>>> x = D()
>>> x.attr
2
(總結:
1:經典類的深度優先,子類繼承多個父類的時候,如果繼承的多個類中有屬性相同的,那么排在第一的父類的屬性會覆蓋后面繼承的類的屬性,也就是如果集成的多個父類屬性相同,那么以繼承的第一個父類的屬性為主;
2:新式類的廣度優先算法:子類繼承多個父類的時候,如果繼承的多個父類中有屬性相同的,那么越往后繼承的類將會覆蓋前面的類的屬性,也就是后來的繼承的覆蓋前面的;真正發揮了長江后浪推前浪的傳統)
  3. 新式類增加了__slots__內置屬性, 可以把實例屬性的種類鎖定到__slots__規定的范圍之中。
  4. 新式類增加了__getattribute__方法
  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__就像這么一個關系,__init__提供生產的原料self(但並不保證這個原料來源正宗,像上面那樣它用的是另一個不相關的類的__new__方法類得到這個實例),而__init__就用__new__給的原料來完善這個對象(盡管它不知道這些原料是不是正宗的)
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM