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

深入了解 Python 中的 MRO(方法解析顺序)

文章目录

  • 深入了解 Python 中的 MRO(方法解析顺序)
  • 什么是 MRO?
  • 如何计算 MRO?C3 算法的合并规则
    • C3 算法的合并步骤
    • 示例:合并过程解析
  • MRO 解析失败的场景
  • 使用 mro() 方法查看 MRO
    • 示例 1:基本用法
  • 菱形继承与 MRO
    • 示例 2:菱形继承
  • 结合 super() 使用 MRO
    • 示例 3:super() 的底层行为
  • __init__ 方法与 MRO
    • 示例 4:构造函数的调用链
  • 协作多重继承与 Mixin 设计
    • 示例 5:Mixin 类的使用
  • 注意事项与最佳实践
  • 总结
  • 扩展阅读


深入了解 Python 中的 MRO(方法解析顺序)

什么是 MRO?

在 Python 中,MRO(方法解析顺序)是多重继承的核心机制。
它决定了当一个类继承多个父类时,Python 如何解析并决定调用父类的方法。
通过 MRO,Python 确保了在多重继承情况下方法不会发生冲突,且每个父类的方法都能按照预定的顺序正确调用。

Python 使用一种称为 C3 线性化 的算法来计算 MRO,这一算法确保了在多继承中父类方法调用的顺序是明确且无歧义的。对于开发者而言,理解 MRO 有助于写出更清晰、易于维护的面向对象代码。


如何计算 MRO?C3 算法的合并规则

Python 的 MRO 计算通过 C3 线性化 算法实现。C3 算法遵循以下原则:

  1. 子类优先于父类:子类在 MRO 中出现在其父类之前。
  2. 声明顺序保留:如果一个类继承多个父类,则父类的顺序在 MRO 中保持不变。
  3. 单调性:所有父类的 MRO 顺序应与其子类的 MRO 一致。

C3 算法的合并步骤

以类 class D(B, C) 为例,C3 算法的合并过程如下:

  1. 递归计算所有父类的 MRO 列表:L(B)L(C)
  2. 合并规则为:
    L(D) = D + merge(L(B), L(C), [B, C])
    
    • merge 操作依次从各列表的头部选择第一个合法候选(不破坏继承顺序的类)。
    • 重复直到所有类被合并。

示例:合并过程解析

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass# L(A) = [A, object]
# L(B) = [B, A, object]
# L(C) = [C, A, object]
# L(D) = D + merge([B, A, object], [C, A, object], [B, C])
# 合并结果:[D, B, C, A, object]

MRO 解析失败的场景

当类的继承关系导致无法满足 C3 算法的原则时,Python 会抛出 TypeError。例如:

class A: pass
class B(A): pass
class C(A, B): pass  # 错误!无法创建一致的MRO

输出

TypeError: Cannot create a consistent method resolution order (MRO) for bases A, B

在这里插入图片描述

分析
C 继承 AB,而 B 本身继承 A。此时 C 的父类顺序要求 AB 之前(因为 A 是第一个父类),但 B 作为 A 的子类又需要在 A 之后,导致矛盾。


使用 mro() 方法查看 MRO

Python 提供了 mro() 方法和 __mro__ 属性来查看类的 MRO。

示例 1:基本用法

class A: pass
class B(A): pass
class C(A): pass
class D(B, C): passprint(D.mro())        # 输出: [D, B, C, A, object]
print(D.__mro__)      # 输出: (D, B, C, A, object)

在这里插入图片描述


菱形继承与 MRO

菱形继承是多重继承中的经典问题,C3 算法能有效解决其方法调用顺序。

示例 2:菱形继承

class A:def method(self):print("A")class B(A):def method(self):super().method()print("B")class C(A):def method(self):super().method()print("C")class D(B, C):def method(self):super().method()print("D")d = D()
d.method()

输出

A
C
B
D

在这里插入图片描述

分析
MRO 顺序为 D → B → C → A → objectsuper()B 中调用 Cmethod,而非直接跳到 A,避免了重复调用。


结合 super() 使用 MRO

super() 函数按 MRO 顺序调用下一个类的方法,而非固定父类。

示例 3:super() 的底层行为

class A:def greet(self):return "Hello from A"class B(A):def greet(self):return super().greet() + " and B"class C(A):def greet(self):return super().greet() + " and C"class D(B, C):def greet(self):return super().greet() + " and D"print(D().greet())    # 输出: Hello from A and C and B and D
print(D.mro())        # 输出: [D, B, C, A, object]

在这里插入图片描述


init 方法与 MRO

MRO 同样影响构造函数的调用顺序。

示例 4:构造函数的调用链

class A:def __init__(self):print("A initialized")class B(A):def __init__(self):super().__init__()print("B initialized")class C(A):def __init__(self):super().__init__()print("C initialized")class D(B, C):def __init__(self):super().__init__()print("D initialized")d = D()

输出

A initialized
C initialized
B initialized
D initialized

在这里插入图片描述


协作多重继承与 Mixin 设计

Mixin 类是一种常见设计模式,需遵循 MRO 规则。

示例 5:Mixin 类的使用

class LoggingMixin:def log(self, message):print(f"Log: {message}")class DataProcessor:def process(self, data):return data.upper()class EnhancedProcessor(LoggingMixin, DataProcessor):def process(self, data):self.log("Processing data")return super().process(data)processor = EnhancedProcessor()
print(processor.process("test"))  # 输出: Log: Processing data → TEST

在这里插入图片描述

最佳实践

  • Mixin 类应放在继承列表最前面。
  • 通过 super() 确保方法链正确传递。

注意事项与最佳实践

  1. 避免过度复杂的继承:优先使用组合或单一继承。
  2. 显式调用父类方法:始终通过 super() 传递方法调用。
  3. 验证 MRO 顺序:通过 mro() 方法确认类的解析顺序。
  4. 历史背景:Python 2 的经典类使用深度优先算法,而 Python 3 的新式类强制使用 C3 算法。

总结

MRO 是 Python 多重继承的基石,C3 算法通过拓扑排序确保了方法调用的合理顺序。理解 super() 的行为、菱形继承的解决方案以及 Mixin 设计模式,能帮助开发者编写高效且可维护的代码。通过 mro() 方法验证类的继承顺序,是规避潜在问题的关键。


扩展阅读

  • Python 官方文档:多重继承
  • C3 线性化算法原理解析

相关文章:

深入了解 Python 中的 MRO(方法解析顺序)

文章目录 深入了解 Python 中的 MRO(方法解析顺序)什么是 MRO?如何计算 MRO?C3 算法的合并规则C3 算法的合并步骤示例:合并过程解析 MRO 解析失败的场景使用 mro() 方法查看 MRO示例 1:基本用法 菱形继承与…...

如何防止 Instagram 账号被盗用:安全设置与注意事项

如何防止 Instagram 账号被盗用:安全设置与注意事项 在这个数字化时代,社交媒体平台如 Instagram 已成为我们日常生活的一部分。然而,随着网络犯罪的增加,保护我们的在线账户安全变得尤为重要。以下是一些关键的安全设置和注意事…...

采样算法二:去噪扩散隐式模型(DDIM)采样算法详解教程

参考 https://arxiv.org/pdf/2010.02502 一、背景与动机 去噪扩散隐式模型(DDIM) 是对DDPM的改进,旨在加速采样过程同时保持生成质量。DDPM虽然生成效果优异,但其采样需迭代数百至数千次,效率较低。DDIM通过以下关键…...

各种类型网络安全竞赛有哪些 网络安全大赛的简称

本文是对入门学习的一些概念了解和一些常规场景记录 1.CTF(capture the flag)是夺旗赛的意思。 是网络安全技术人员之间进行攻防的比赛。 起源1996年DEFCON全球黑客大会,替代之前真实攻击的技术比拼。 (DEFCON极客大会诞生1993,…...

包子凑数——蓝桥杯真题Python

包子凑数 输入输出样例 示例 1 输入 2 4 5输出 6样例说明 凑不出的数目包括:1, 2, 3, 6, 7, 11。 示例 2 输入 2 4 6输出 INF样例说明 所有奇数都凑不出来,所以有无限多个 运行限制 最大运行时间:1s最大运行内存: 256M 最大公约数 最大公…...

网络通信/IP网络划分/子网掩码的概念和使用

文章目录 概述子网的考题子网掩码的历史有/无类地址子网划分!子网掩码超网技术/CIDR子网掩码和路由IP子网掩码定义 网络规划网络规划-拆子网网络规划-组超网子网划分案例 区分于其他特殊IP地址IP地址和网络地址子网掩码和网络地址子网掩码和广播地址 子网间的通信其他 概述 本…...

【前端】简单原生实例合集html,css,js

长期补充,建议关注收藏点赞。 目录 分栏input各种类型iframe表单拖拽 分栏 区分fieldset和framesetframeset是把浏览器窗口分成几个区域,每个区域分别放置一个html文档到对应的frame中,而且这个比例可以按住边栏进行调整col指定左右边栏的宽…...

MySQL--》如何在MySQL中打造高效优化索引

目录 初识索引 索引结构 性能分析 索引使用 最左前缀法则 SQL提示使用 覆盖索引使用 前缀索引使用 索引失效情况 初识索引 索引(index):是帮助MySQL高效获取数据的数据结构(有序),在数据之外数据库系统还维护着满足特定查找算法的数据结构&…...

盛京开源社区加入 GitCode,书写东北开源生态新篇章

在数字化转型与开源技术蓬勃发展的浪潮下,开源社区已成为推动技术创新的核心力量。盛京开源社区(SJOSC)作为沈阳地区的开源交流平台,始终致力于连接开发者、企业及高校,构建区域技术生态圈。 现在,盛京开源…...

HTML转义和反转义工具类

HTML转义和反转义工具类 package com.common.utils;import cn.hutool.http.HTMLFilter; import org.apache.commons.lang3.StringUtils;/*** 转义和反转义工具类** author lxx*/ public class EscapeUtil {public static final String RE_HTML_MARK "(<[^<]*?>…...

网络运维学习笔记(DeepSeek优化版)005网工初级(HCIA-Datacom与CCNA-EI)链路层发现协议与VLAN技术

文章目录 一、链路层发现协议1.1 思科CDP协议1.2 华为LLDP协议 二、VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;技术详解2.1 基本概念2.2 技术特性2.3 接口工作原理2.3.1 Access模式2.3.2 Trunk模式 2.4 厂商配置对比思科配置华为配置 2.5 …...

DeepSeek开源周Day4:三连发!突破 AI 训练瓶颈的立体解决方案,并行计算三剑客DualPipe、EPLB与Profile-data

项目地址&#xff1a; https://github.com/deepseek-ai/DualPipehttps://github.com/deepseek-ai/eplbhttps://github.com/deepseek-ai/profile-data 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (4/5)&#xff01; ​ ​ 一、背景概述 …...

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…...

RabbitMQ操作实战

1.RabbitMQ安装 RabbitMQ Windows 安装、配置、使用 - 小白教程-腾讯云开发者社区-腾讯云下载erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安装RabbitMQ及延时消息插件rabbitmq_delayed_message_exch…...

IO 和 NIO 有什么区别?

文章目录 阻塞模式与非阻塞模式数据处理方式通信模型应用场景 阻塞模式与非阻塞模式 IO&#xff1a;是阻塞式的 IO 操作。在传统的 IO 中&#xff0c;当一个线程执行读操作或者写操作时&#xff0c;该线程会被阻塞&#xff0c;直到操作完成。例如&#xff0c;在从文件读取数据…...

OpenWebUI配置异常的外部模型导致页面无法打开

一、使用Ollama关闭OpenAI OpenWebUI自带OpenAI的API设置&#xff0c;且默认是打开的&#xff0c;默认情况下&#xff0c;启动后&#xff0c;会不断的去连https://api.openai.com/v1&#xff0c;但是无法连上&#xff0c;会报错&#xff0c;但是不会影响页面&#xff0c;能正常…...

2025年度福建省职业院校技能大赛高职组“信息安全管理与评估”赛项规程样题模块二

模块二 网络安全事件响应、数字取证调查、应用程序安全 竞赛项目赛题 本文件为信息安全管理与评估项目竞赛-第二阶段样题&#xff0c;内容包括&#xff1a;网络安全事件响应、数字取证调查。 本次比赛时间为90分钟。 介绍 竞赛有固定的开始和结束时间&#xff0c;参赛队伍必须…...

鸿蒙兼容Mapbox地图应用测试

鸿蒙Next已经发布一段时间了&#xff0c;很多之前的移动端地图应用&#xff0c;纷纷都要求适配鸿蒙Next。作为开发者都清楚&#xff0c;所谓的适配其实都是重新开发&#xff0c;鸿蒙的开发语言和纯前端的Javascript不同&#xff0c;也可以Android原始开发的语言不同。鸿蒙自带的…...

java练习(45)

ps:题目来自力扣 两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断…...

面试之《前端开发者如何优化页面的加载时间?》

前端开发者可以从多个方面入手优化页面的加载时间&#xff0c;以下是一些常见且有效的方法&#xff1a; 优化资源加载 压缩资源文件&#xff1a;对 HTML、CSS、JavaScript 文件进行压缩&#xff0c;去除不必要的空格、注释等&#xff0c;减小文件体积&#xff0c;加快下载速度…...

部署Flink1.20.1

1、设置环境变量 export JAVA_HOME/cluster/jdk export CLASSPATH.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jarp #export HIVE_HOME/cluster/hive export MYSQL_HOME/cluster/mysql export HADOOP_HOME/cluster/hadoop3 export HADOOP_CONF_DIR$HADOOP_HOME/etc/hadoop …...

iOS自归因详细介绍

iOS自归因详细介绍 自归因&#xff08;Self-Attribution&#xff09;是指应用或广告平台通过分析用户行为数据&#xff0c;确定用户安装应用的来源渠道。在iOS生态中&#xff0c;由于隐私政策的限制&#xff08;如App Tracking Transparency&#xff0c;ATT&#xff09;&#…...

影视后期工具学习之PR

pr剪辑之旅 第一节课 入门基础知识 1.了解影视基础术语 2.PR面板&首选项设置 首选项需要设置的选项: 自动保存: 修剪: 媒体: 媒体缓存: 经典面板设置,可以根据个人喜好做出改变: 3.展示与准备工作 新建序列:1.横板序列 2.竖版序列:</...

浏览器JS打不上断点,一点就跳到其他文件里。浏览器控制台 js打断点,指定的位置打不上断点,一打就跳到其他地方了。

关闭JavaScript 源代码映射&#xff0c;F12开发者模式 设置->偏好设置->源代码/来源->JavaScript 源代码映射。 肯定不是这个原因导致的&#xff0c;但这个办法可以暂时解决问题&#xff0c;点完这个东西就隐藏了webpack&#xff0c;有懂的来讲讲。 又浪费一个小时…...

XXE漏洞:原理、危害与修复方法详解

目录 一、XXE漏洞概述二、XXE漏洞原理三、XXE漏洞危害1. 任意文件读取2. 命令执行3. 拒绝服务攻击(DoS)4. SSRF攻击四、XXE漏洞修复方法1. 禁用外部实体JavaPythonPHP2. 输入验证和过滤3. 安全配置服务器4. 升级解析器版本五、总结一、XXE漏洞概述 XXE(XML External Entity…...

C#与AI的交互(以DeepSeek为例)

C#与ai的交互 与AI的交互使用的Http请求的方式&#xff0c;通过发送请求&#xff0c;服务器响应ai生成的文本 下面是完整的代码&#xff0c;我这里使用的是Ollama本地部署的deepseek&#xff0c;在联网调用api时&#xff0c;则url会有不同 public class OllamaRequester {[Se…...

Qt——使用QtConcurrent::run开启的线程,程序退出后仍在后台运行的解决方法(QFutureWatcher监视线程)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实...

DeepSeek-R1:通过强化学习激发大语言模型的推理能力

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列三DeepSeek大模型技术系列三》DeepSeek-…...

Xcode如何高效的一键重命名某个关键字

1.选中某个需要修改的关键字&#xff1b; 2.右击&#xff0c;选择Refactor->Rename… 然后就会出现如下界面&#xff1a; 此时就可以一键重命名了。 还可以设置快捷键。 1.打开Settings 2.找到Key Bindings 3.搜索rename 4.出现三个&#xff0c;点击一个地方设置后其…...

smolagents学习笔记系列(八)Examples - Master you knowledge base with agentic RAG

这篇文章锁定官网教程中 Examples 章节中的 Master you knowledge base with agentic RAG 文章&#xff0c;主要介绍了如何将 agent 和 RAG 结合使用。 官网链接&#xff1a;https://huggingface.co/docs/smolagents/v1.9.2/en/examples/rag&#xff1b; Agentic RAG 在之前的…...