Python新式类与经典类的核心差异解析
本文详细解析Python中经典类与新式类的区别,重点阐述多重继承下的深度优先与C3算法差异,以及实例类型判断的不同。指出Python 3中所有类均为新式类,统一了类与类型的关系,并提供了相关代码验证。
新式类与经典类的定义与Python3变化
1.新式类与经典类
在Python 2及更早版本中,若一个类直接或间接继承自任意内置类型(即内置类型出现在该类的继承树中),则被归类为“新式类”,并具备新式类的所有特性;反之,若不继承自任何内置类型,则被称为“经典类”。
自Python 3起,新式类与经典类的区分已不再存在。在Python 3.x及后续版本中,所有类均隐式继承自内置类型object(即使未显式声明继承object),因此所有类均被视为“新式类”。
官方文档 https://www.python.org/doc/newstyle/
多重继承中的搜索顺序差异
2.继承顺序的区别
这一区别主要在涉及多重继承的场景下显现。
经典类采用深度优先(Depth-First Search, DFS)策略进行搜索,即从当前类向下追溯至基类;而新式类则采用C3算法进行线性化(并非简单的广度优先)。
以下代码用于验证经典类的行为(注意:所有经典类相关代码需在Python 2环境下运行,下文同理)。定义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,搜索继续向上追溯至其父类ClassicClassA,并在其中找到var属性后停止搜索。此时,var的值取自ClassicClassA;而ClassicClassC中定义的var属性则从未被检索到。
运行结果证实,输出内容为Classic Class A,表明经典类的继承搜索机制为深度优先,且搜索方向为由下至上。
Classic Class A
新式类的继承顺序并非广度优先,而是遵循C3算法。在某些特定结构下,C3算法的计算结果可能与广度优先的预期结果一致,但这并非普遍规律。
通过以下代码验证新式类的继承搜索顺序。新式类提供了mro()方法以查看类的解析顺序(Method Resolution Order),这也是新式类的一个显著特征,例如调用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中已彻底解决。由于Python 3中所有类均为新式类,类与类型的概念得以统一:类实例的类型即为其所属的类(通常与实例的__class__属性一致),不再使用Python 2.x中的“instance”这一独立实例类型。
更详细的:https://www.jb51.net/article/165048.htm
总结
以上就是本文的全部内容,希望本文的解析对您的学习或工作具有参考价值,感谢支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









