当前位置: 首页 > backend >正文

python 执行顺序

什么是 MRO?

MRO (方法解析顺序) 是 Python 用来在多继承情况下决定方法查找顺序的规则。它定义了解决方法或属性时的搜索顺序——即在类继承关系中先搜索哪个类的定义。

  • MRO 遵循 C3 线性化算法(也叫 C3 Superclass Linearization)。
  • 它始终优先查找:
    1. 当前类
    2. 直接父类(从左到右)。
    3. 间接父类(基于 C3 算法计算)。

你可以通过 ClassName.__mro__inspect.getmro(ClassName) 查看类的 MRO。

基本示例

class A:def show(self):print("A show")class B(A):def show(self):print("B show")class C(A):def show(self):print("C show")class D(B, C):  # D 继承 B 和 Cpassd = D()
d.show()

分析:

  1. D 继承了 BC,而且 BC 都继承了 A
  2. D 的 MRO 是什么?通过 D.__mro__ 查看:
    print(D.__mro__)
    
    输出:
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    
  3. 当调用 d.show() 时,Python 按照 MRO 顺序查找方法:
    • 首先在类 D 中查找,但类 D 没有定义 show 方法。
    • 接着查找 B 类,发现 B 定义了 show 方法,于是执行 Bshow,输出:
      B show
      

更复杂的继承关系

让我们看一个更加复杂的多继承例子。

class X:def show(self):print("X show")class Y(X):def show(self):print("Y show")class Z(X):passclass P(Y, Z):  # P 继承 Y 和 Zpassp = P()
p.show()print(P.__mro__)  # 查看 MRO

分析:

  1. P 继承了 YZ,而 YZ 又都继承了 X
  2. P 的 MRO 是啥?通过 print(P.__mro__) 可以查看:
    (<class '__main__.P'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.X'>, <class 'object'>)
    
  3. 当调用 p.show() 时,Python 遵循 MRO:
    • 先查找 P,发现没有 show 方法。
    • 接着查找 Y,找到 Y 中的 show 方法,执行输出:
      Y show
      

为什么遵循 C3 线性化算法?

Python 使用 C3 线性化算法 是为了确保:

  1. 继承的顺序一致性:类的顺序不能随便更改,保证了 “左优先”、父类优先。
  2. 单一继承路径:即在搜索属性和方法时,某个类不会被重复访问。

示例:解释 MRO 的计算

让我们看一个更加复杂的例子来理解 MRO 的计算规则:

class A:  # 顶层基类passclass B(A):passclass C(A):passclass D(B, C):  # 多继承passprint(D.__mro__)  # 输出 MRO

分析:
为了计算 D 的 MRO,C3 线性化算法会按以下步骤进行:

  1. D 开始,将所有直接基类合并,优先选第一个未使用的类。
    • D 继承了 BC,因此顺序为:D -> B -> C
  2. 再往上层,BC 的父类都是 A,而 A 的 MRO 是 [A, object]
  3. 最终计算完成后,D 的 MRO 是:
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    

总结图解:
MRO 按如下层级组织:

D
|--> B
|    |--> A
|
|--> C|--> A

其中,公共父类 A 存在于 BC 中,但只出现一次。

实例->类->父类(实例属性优先,类属性次之)

class Vector:typecode = 'd'  # 表示数组存储的元素类型为双精度浮点数def **init**(self, components):  """构造函数,接受任意可迭代对象作为 components"""self._components = array(self.typecode, components)

在 Python 中,当我们通过 self.typecode 访问一个属性时,Python 会按照以下规则逐层查找该属性:

  1. 实例的属性字典 (__dict__):首先,访问实例自己的属性。也就是说,Python 会检查当前实例是否有 typecode 这个属性。如果实例中找到了,就会直接返回。
    例如:

    v = Vector([1.0, 2.0, 3.0])
    v.typecode = 'f'  # 如果我们给实例设置了新的 `typecode`,它会优先被使用
    
  2. 类的属性:如果实例中没有找到 typecode,Python 会去类中查找是否声明了 typecode
    在你的代码中,类的 typecode 属性被声明为类变量:

    typecode = 'd'
    
  3. 父类的属性:如果在类中也没有找到,Python 会继续向父类(基类)中查找。这种机制是 Python 的方法解析顺序(MRO,Method Resolution Order)。

  4. 抛出 AttributeError 异常:如果以上步骤都未找到,则会抛出 AttributeError

在你提到的例子中:

self.typecode

这个过程是:

  • 首先检查实例变量中是否存在一个名为 typecode 的变量。如果没有:
  • 再检查当前类中是否有 typecode。在这里,它会发现 typecode = 'd',于是返回该值。

因此,这个查找流程和机制解释了为什么会从实例开始,然后逐步向类属性查找逻辑。


你也可以通过以下代码验证这个流程:

class Vector:typecode = 'd'  # 类变量def __init__(self, components):self._components = components# 测试代码
v = Vector([1.0, 2.0, 3.0])
print(v.typecode)  # 打印类变量 'd'v.typecode = 'f'  # 修改实例的 typecode
print(v.typecode)  # 打印实例变量 'f'
print(Vector.typecode)  # 打印类变量,仍然是 'd'

运行结果会是:

d
f
d

这说明:

  1. 修改 v.typecode 只修改了实例的 typecode,并未影响类的 typecode
  2. 当实例中没有 typecode 时,会回退到类中查找。

总结:Python 是动态语言,类变量和实例变量之间通过这种查找顺序建立了一个灵活的机制。

http://www.xdnf.cn/news/1063.html

相关文章:

  • 程序员学商务英文之Terms of Payment Packing
  • 日志文件太大,如何分卷压缩便于传输
  • pwm驱动呼吸灯
  • 【NCCL】transport建立(一)
  • Express项目实战大事件后台 API 项目(五)——文章管理
  • java集合框架day1————集合体系介绍
  • 服务器监控软件推荐
  • Python Cookbook-6.7 有命名子项的元组
  • RAG vs 微调:大模型定制化技术选型全解析
  • 10、Context:跨维度传音术——React 19 状态共享
  • 【Java核心技术卷Ⅰ-第11版学习-第3章-Java的基本程序设计结构】
  • 每日一题(9) 垃圾箱分布
  • 基于SpinrgBoot+Vue的智慧农业管理平台-031
  • 远程医疗系统如何有效防护CC攻击
  • 智慧教室电子班牌-智能管理系统源码,‌后端‌基于Spring Boot框架,前端‌使用Vue.js框架进行组件化开发
  • 在python中装饰器的使用
  • File工具总结
  • 悟空黑桃A邀请码(31187835)
  • VSCode远程图形化GDB
  • 算法 | 鲸鱼优化算法(WOA)与强化学习的结合研究
  • Dify-web开发思路
  • Pikachu靶场-SQL注入
  • STM32——相关软件安装
  • 【Linux】:HTTPS协议
  • 相机标定(输出相机内参和畸变参数)
  • ASP.NET 中防止用户多次登录的方法
  • wkhtmltopdf - HTML转PDF/图像命令行工具
  • python@staticmethod 是什么含义?
  • Coze平台​ 创建AI智能体的详细步骤指南
  • 多源异构网络安全数据(CAPEC、CPE、CVE、CVSS、CWE、ATTCK、D3FEND)的详细解析,包括其作用、数据内容及相互联系