在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性,反之,即不由任意内置类型派生出的类,则称之为“经典类”。
"新式类”和“经典”类的区分在Python 3之后就已经不存在,在Python 3. x之后的版本,因为所有的类都派生自内置类型对象(即使没有显示的继承对象类型),即所有的类都是“新式类”。
官方文档https://www.python.org/doc/newstyle/
主要是在多重继承时才会遇到这个问题。
经典类的钻石继承是深度优先,即从下往上搜索;新式类的继承顺序是采用C3算法(非广度优先)。
对经典类进行代码验证(所有经典类的代码必须在Python2下运行,下同),ClassicClassB继承自ClassicClassA, SubClassicClass继承自ClassicClassB, ClassicClassC:
类ClassicClassA (): var=经典类的 类ClassicClassB (ClassicClassA): 通过 类ClassicClassC (): var='经典类C ' 类SubClassicClass (ClassicClassB ClassicClassC): 通过 if __name__==癬_main__”: 打印(SubClassicClass.var)
在SubClassicClass对var属性进行搜索的过程中,根据从下到上的原则,会优先搜索ClassicClassB,而ClassicClassB没有var属性,会继续往上搜索ClassicClassB的超类ClassicClassA,在ClassicClassA中发现var属性后停止搜索,var的值为ClassicClassA中变量的值,而ClassicClassC的var属性从始至终都未被搜索到。
从运行结果可以看的出,输出的是经典的类,可见类继承的搜索是深度优,先由下至上进行搜索。
经典类A
引用>新式类的继承顺序并非是广度优先,而是C3算法,只是在部分情况下,C3算法的结果恰巧与广度优先的结果相同。
对新式类的继承搜索顺序进行代码验证,新式类中,可以使用mro函数来查看类的搜索顺序(这也算是一个区别),如SubNewStyleClass.mro ()。
类NewStyleClassA(对象): var='新样式类' 类NewStyleClassB (NewStyleClassA): 通过 类NewStyleClassC (NewStyleClassA): var='新样式类C ' 类SubNewStyleClass (NewStyleClassB NewStyleClassC): 通过 if __name__==癬_main__”: print (SubNewStyleClass.mro ()) 打印(SubNewStyleClass.var)从代码运行结果看,恰巧与从左至右的广度优先预期结果相同。
[& lt;类__main__.SubNewStyleClass的祝辞,& lt;类__main__.NewStyleClassB的祝辞,& lt;类__main__.NewStyleClassC的祝辞,& lt;类__main__.NewStyleClassA的祝辞,& lt;类型对象的祝辞]
引用>
新风格类C
但是不代表新式类的继承顺序就是广度优先,可以稍微修改下代码进行验证:NewStyleClassC改为继承自对象
类NewStyleClassA(对象): var='新样式类' 类NewStyleClassB (NewStyleClassA): 通过 类NewStyleClassC(对象): var='新样式类C ' 类SubNewStyleClass (NewStyleClassB NewStyleClassC): 通过 if __name__==癬_main__”: print (SubNewStyleClass.mro ()) 打印(SubNewStyleClass.var)运行结果不再符合广度优先:
[& lt;类__main__.SubNewStyleClass的祝辞,& lt;类__main__.NewStyleClassB的祝辞,& lt;类__main__.NewStyleClassA的祝辞,& lt;类__main__.NewStyleClassC的祝辞,& lt;类型对象的祝辞]
引用>
新样式类
可见,新式类的继承顺序并非广度优先,而是C3算法。至于C3算法,以后再另外详细写。
在经典类中,所有的类都是classobj类型,而类的实例都是实例类型。类与实例只有通过__class__进行属性进行关联。这样在判断实例类型时,就会造成不便:所有的实例都是实例类型。
甲级():通过 B类():通过=() b=b () if __name__==癬_main__”: print(类型(a)) 打印((b)型) 打印(类型(a)==类型(b))类型(a)==类型(b)的结果永远为真,那这样的比较就毫无意义。
更为麻烦的是,经典类的实例是实例类型,而内置类的实例却不是,无法统一。
Python中新式类与经典类的区别详析