Python新式類與經典類的區別


1.新式類與經典類

 

在Python 2及以前的版本中,由任意內置類型派生出的類(只要一個內置類型位於類樹的某個位置),都屬於“新式類”,都會獲得所有“新式類”的特性;反之,即不由任意內置類型派生出的類,則稱之為“經典類”。

“新式類”和“經典類”的區分在Python 3之后就已經不存在,在Python 3.x之后的版本,因為所有的類都派生自內置類型object(即使沒有顯示的繼承object類型),即所有的類都是“新式類”。

官方文檔 https://www.python.org/doc/newstyle/

 

2.繼承順序的區別

 

主要是在多重繼承時才會遇到這個問題。

經典類的鑽石繼承是深度優先,即從下往上搜索;新式類的繼承順序是采用C3算法(非廣度優先)。

 

對經典類進行代碼驗證(所有經典類的代碼必須在Python2下運行,下同),ClassicClassB 繼承自 ClassicClassA,SubClassicClass繼承自ClassicClassB,ClassicClassC:

class ClassicClassA():
    var = 'Classic Class A'


class ClassicClassB(ClassicClassA):
    pass


class ClassicClassC():
    var = 'Classic Class C'


class SubClassicClass(ClassicClassB, ClassicClassC):
    pass


if __name__ == '__main__':
    print(SubClassicClass.var)

在SubClassicClass對var屬性進行搜索的過程中,根據從下到上的原則,會優先搜索ClassicClassB,而ClassicClassB沒有var屬性,會繼續往上搜索ClassicClassB的超類ClassicClassA,在ClassicClassA中發現var屬性后停止搜索,var的值為ClassicClassA中var的值;而ClassicClassC的var屬性從始至終都未被搜索到。

從運行結果可以看出,輸出的是Classic Class A,可見類繼承的搜索是深度優先,由下至上進行搜索。

Classic Class A

 

新式類的繼承順序並非是廣度優先,而是C3算法,只是在部分情況下,C3算法的結果恰巧與廣度優先的結果相同。

對新式類的繼承搜索順序進行代碼驗證,新式類中,可以使用mro函數來查看類的搜索順序(這也算是一個區別),如SubNewStyleClass.mro()。

class NewStyleClassA(object):
    var = 'New Style Class A'


class NewStyleClassB(NewStyleClassA):
    pass


class NewStyleClassC(NewStyleClassA):
    var = 'New Style Class C'


class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
    pass


if __name__ == '__main__':
    print(SubNewStyleClass.mro())
    print(SubNewStyleClass.var)

從代碼運行結果看,恰巧與從左至右的廣度優先預期結果相同。

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassC'>, <class '__main__.NewStyleClassA'>, <type 'object'>]
New Style Class C

但是不代表新式類的繼承順序就是廣度優先,可以稍微修改下代碼進行驗證:NewStyleClassC改為繼承自object

class NewStyleClassA(object):
    var = 'New Style Class A'


class NewStyleClassB(NewStyleClassA):
    pass


class NewStyleClassC(object):
    var = 'New Style Class C'


class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
    pass


if __name__ == '__main__':
    print(SubNewStyleClass.mro())
    print(SubNewStyleClass.var)

運行結果不再符合廣度優先:

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class '__main__.NewStyleClassC'>, <type 'object'>]
New Style Class A

可見,新式類的繼承順序並非廣度優先,而是C3算法。至於C3算法,以后再另外詳細寫。

 

3.類實例類型的區別

 

在經典類中,所有的類都是classobj類型,而類的實例都是instance類型。類與實例只有通過__class__屬性進行關聯。這樣在判斷實例類型時,就會造成不便:所有的實例都是instance類型。

class A():pass
class B():pass

a = A()
b = B()

if __name__ == '__main__':
    print(type(a))
    print(type(b))
    print(type(a) == type(b))

type(a) == type(b)的結果永遠為True,那這樣的比較就毫無意義。

更為麻煩的是,經典類的實例是instance類型,而內置類的實例卻不是,無法統一。

通過代碼判斷下內置類型list的實例[1, 2, 3]是什么類型

print(type([1, 2, 3]))

運行結果,是list類型

<type 'list'>

內置類的實例類型和經典類的實例類型完全不同,容易造成困惑,不利於代碼的統一。

這個問題在Python 3之后就不復存在了,因為Python3中所有的類都是新式類,新式類中類與類型已經統一:類實例的類型是這個實例所創建自的類(通常是和類實例的__class__相同),而不再是Python 2.x版本中的“instance”實例類型。

更詳細的:http://www.cnblogs.com/blackmatrix/p/5594109.html

 

 

大概就想到這幾點,其他的有想到再補充。


免責聲明!

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



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