Python新式类与经典类的核心差异解析

花开有时
花开有时
发布时间:2026-10-14| 6人浏览过
原创

本文详细解析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

总结

以上就是本文的全部内容,希望本文的解析对您的学习或工作具有参考价值,感谢支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。