python C3算法

news/2024/10/24 14:18:29/文章来源:https://www.cnblogs.com/hnu-hua/p/18499493

Python MRO

C3算法是python当中计算类继承顺序的一个算法,从python2.3以后就一直使用此算法了。

c3 linearization算法称为c3线性化算法

C3算法原理

首先定义几个符号的意义:

符号 意义
L 针对一个类进行解析用L进行表示,例如L(A)表示对类A进行解析
merge 合并操作的一个函数(后面具体介绍)
C 表示一个类名
B 表示是C的一个子类,如果多个子类用B1,B2....表示
+ 元素列表顺序添加
tail 去除列表第一个元素,例如 tail([1,2,3,4]) = [2,3,4]
L(C) = C + merge(L(B1) + L(B2) + ...+ )

merge函数合并规则:

  1. 首先选中merge 函数的第一个参数(也是一个列表),按照公式里的描述就是L(B1)。
  2. 取列表中第一个元素记为h,如果h没有出现其他 列表的tail中, 那么将其移到 merge函数前,提取出来,并且将这个元素在所有列表中移除,并重复 2。
  3. 如果出现在其他列表中的 tail 中,寻找下一个列表。
  4. merge 函数所有元素都被移除类创建成功,如果寻找不到下一个列表则创建失败。

下面举例说明:

image-20241024135943911

class X():passclass Y():passclass A(X, Y):passclass B(X, Y):passclass F(A, B):pass
print(F.__mro__)

我们来解析 F的mro顺序,则首先记为 L(F),根据

L(C) = C + merge(L(B1) + L(B2) + ...+ )

公式得到:

L(F) = F + merge(L(A)+L(B))

接下来计算L(A),与L(B):

L(A) = A + merge(L(X),L(Y)) = A + merge([X],[Y]) = [A,X,Y]
L(B) = B + merge(L(X),L(Y)) = B + merge([X],[Y]) = [B,X,Y]

带入 L(F) = L(F) + merge(L(A)+L(B)) 得到:

L(F) = F + merge([A,X,Y],[B,X,Y])

下面是关键merge逻辑理解了,首先根据 merge 的说明 1,选中得到 [A,X,Y], 根据merge的说明2,选中第一个元素 A, 判断A 是否在 tail(B,X,Y) 中,即 A 是否在 [X,Y] 中,不在,将其提出来,得到:

L(F) = F + merge([A,X,Y],[B,X,Y]) = [F,A] + merge([X,Y],[B,X,Y])

接着重复 merge的2,判断 X 是否在 tail(B,X,Y)=[X,Y] 中,结果是存在,那么寻找[X,Y]的下一个列表,即[B,X,Y],判断B 是否存在 tail([X,Y])=[Y] 中,不存在,提出B,得到:

L(F) = F + merge([A,X,Y],[B,X,Y]) = [F,A] + merge([X,Y],[B,X,Y]) = [F,A,B] + merge([X,Y],[X,Y])

剩下逻辑一样,依次提出 X和Y:

L(F) = F + merge([A,X,Y],[B,X,Y]) = [F,A] + merge([X,Y],[B,X,Y]) = [F,A,B] + merge([X,Y],[X,Y]) = [F,A,B,X,Y]

可以将我上述python代码运行一下结果和我们手算的是一样的:

(<class '__main__.F'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.X'>, <class '__main__.Y'>, <class 'object'>)

复杂的解析(练手逻辑)

image-20241024140042488

L(K1) = K1 + merge(L(C), L(A), L(B))= K1 + merge([C, O], [A, O], [B, O])= [K1, C] + merge([O], [A, O], [B, O])= [K1, C, A] + merge([O], [O], [B, O])= [K1, C, A, B] + merge([O], [O], [O])= [K1, C, A, B, O]
L(K2) = [K2, B,D,E, O]
L(K3) = [K3,A, D, O]
L(Z)  = Z + merge(L(K1), L(K3), L(K2))= Z + merge([K1, C, A, B, O],[K3, A, D, O],[K2, B, D, E, O])= [Z, K1] + merge([C, A, B, O], [K3, A, D, O], [K2, B, D, E, O])= [Z, K1, C] + merge([A, B, O], [K3, A, D, O], [K2, B, D, E, O])= [Z K1, C] + merge([A, B, O],  [K3, A, D, O], [K2, B, D,E, O])= [Z, K1, C, K3] + merge([A, B, O], [A, D, O], [K2, B, D, E, O])= [Z, K1, C, K3, A] + merge([B, O], [D, O],  [K2, B, D, E, O])= [Z,K1, C, K3, A, K2] + merge([B, O], [D, O], [B, D, E, O])= [Z,K1, C, K3, A, K2, B] + merge([O], [D, O], [D, E, O])= [Z, K1,C, K3, A, K2, B, D] + merge([O], [O], [E,O])= [Z, K1,C, K3, A, K2, B, D, E, O]
class O:passclass C(O):passclass A(O):passclass B(O):passclass D(O):passclass E(O):passclass K1(C,A,B):passclass K3(A,D):passclass K2(B,D,E):passclass Z(K1,K3,K2):passprint(Z.__mro__)

手写C3算法

def c3MRO(cls):if cls is object:# 讨论假设顶层基类为object,递归终止return [object]# 构造C3-MRO算法的总式,递归开始mergeList = [c3MRO(baseCls) for baseCls in cls.__bases__]mergeList.append(list(cls.__bases__))mro = [cls] + merge(mergeList)return mrodef merge(inLists):if not inLists:# 若合并的内容为空,返回空list# 配合下文的排除空list操作,递归终止return []# 遍历要合并的mrofor mroList in inLists:# 取headhead = mroList[0]# 遍历要合并的mro(与外一层相同),检查尾中是否有head### 此处也遍历了被取head的mro,严格地来说不符合标准算法实现### 但按照多继承中地基础规则(一个类只能被继承一次),### head不可能在自己地尾中,无影响,若标准实现,反而增加开销for cmpList in inLists[inLists.index(mroList) + 1:]:if head in cmpList[1:]:breakelse:# 筛选出好headnextList = []for mergeItem in inLists:if head in mergeItem:mergeItem.remove(head)if mergeItem:# 排除空listnextList.append(mergeItem)# 递归开始return [head] + merge(nextList)else:# 无好head,引发类型错误raise TypeError

参考文章:

c3 linearization详解 - Hello_wshuo - 博客园

Python多重继承问题之MRO和C3算法_Python_王坤祥_InfoQ写作社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/821184.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我与信竞

抱歉,刚开始就要说再见了。抱歉,刚开始就要说再见了。 我从2020年开始学信竞,至今已有四年多了。 为何现在才开始写博客呢? 答曰:因为我要退役了。 10月26打CSP-S,不出意外的话,一切就快要结束了。 “历经艰辛的飞升者成了围剿孙悟空的十万天兵之一” ,是啊,这世上本不…

2024-10-24 main.js:6 Uncaught TypeError: app is not a function ==》写法错误

vue代码如下:// main.js import { createApp } from vue import ./style.css import App from ./App.vue const app = createApp(App);app().mount(#app)报错:原因:app().mount(#app)写法有误 正确写法应该去掉这个()import { createApp } from vue import ./style.css im…

Cinemachine系列——AimComposer

这个虚拟摄像机的瞄准算法会旋转摄像机,使其朝向指定的“注视”目标。同时,它还会应用偏移量、阻尼效果和构图规则。 主要要点: 朝向目标:摄像机会自动调整其方向,以面向指定的注视目标,例如角色的上脊椎或头骨、车辆,或通过程序控制或动画的虚拟对象。 偏移量:可以为摄…

Qt/C++路径轨迹回放/回放每个点信号/回放结束信号/拿到移动的坐标点经纬度

一、前言说明 在使用百度地图的路书功能中,并没有提供移动的信号以及移动结束的信号,但是很多时候都期望拿到移动的哪里了以及移动结束的信号,以便做出对应的处理,比如结束后需要触发一些对应的操作。经过搜索发现很多人都有这个需求,需要在js文件中加上一点代码才行,也就…

2024-2025-1 20241401 《计算机基础与程序设计》 第五周学习总结

班级链接 2024计算机基础与程序设计作业要求 第五周作业作业目标 ①Pep/9虚拟机 ②机器语言与汇编语言 ③算法与伪代码 ④测试:黑盒,白盒教材学习内容总结 《计算机科学概论》第六章计算机操作:介绍了计算机的基本操作,包括机器语言的基本概念。 机器语言是由一系列二进制代…

Thymeleaf基本使用

https://blog.csdn.net/weixin_45719444/article/details/122891930 介绍 官网:https://www.thymeleaf.org/ Thymeleaf是一个用于Web和独立环境的现代服务器端Java模板引擎。 简单示例打开IDEA,创建一个maven工程(quickstart archetype)。 在pom.xml文件中导入依赖,目前最…

漫谈自动化测试

前几天看到星球里几位同学在讨论各自所在团队的自动化测试实践案例和踩过的坑,蛮有意思的。 比如为了响应领导号召和满足绩效考核,搞各种各样的覆盖率指标;比如为了赶自动化测试覆盖率进度,每个接口和用例象征性的校验一下(甚至不校验不断言),各种各样意想不到的操作。 自…

AUTOSAR架构下,持续集成CI的最佳实践

随着汽车电子技术的快速发展,汽车软件的复杂性与日俱增,如何确保软件开发的高效性与稳定性成为了一个关键问题。为了解决这个问题,许多汽车企业和供应商逐渐引入了AUTOSAR架构,并在此基础上构建了持续集成(CI)流程。今天,我们就来探讨一下基于AUTOSAR架构的CI流程实践,…

哇!树链剖分(重链剖分学习笔记)

听说有人不会树链剖分? 前置芝士线段树 树状数组 Splay FHQ-Treap以上五种任意一种即可,这里主要讲线段树做法。 引入 树链剖分(Tree Line Pow Divide),一种解决树上快速路径修改查询问题的算法,一般指 重链剖分(Heavy Path Decomposition)。 思想图解 一个问题 如题,…

某SCADA系统发电机过速故障研究

某SCADA系统发电机过速故障研究 直观上讲,发电机转速过高故障最显然的特征应该就是“发电机转速”,因此对故障发生时的发电机转速进行可视化研究:如上图所示,对发电机转速进行了 Min-Max 归一化。该次故障报警时,确实存在转速较高的情况,但显然,并非转速高就会报警。通过…

CANOpen协议SDO中止报文(内存不足的解决方法)

今天在开发过程中,使用SDO进行字符串传输的时候出现了错误,检查到SDO服务器返回的报文帧是一个中止帧,中止代码为0x05040005这时候去翻CIA301的手册查中止代码的含义为内存不足经过断点调试跟踪,发现在config.h中是一个配置宏设置的是32,而我的字符串的长度为50,所以就中…

WinDbg快速分析异常情况Dump文件

https://syxdevcode.github.io/2017/12/04/WinDbg%E5%BF%AB%E9%80%9F%E5%88%86%E6%9E%90%E5%BC%82%E5%B8%B8%E6%83%85%E5%86%B5Dump%E6%96%87%E4%BB%B6/WinDbg快速分析异常情况Dump文件 生产环境偶尔会出现一些异常问题,WinDbg 或 GDB 就是解决此类问题的利器。调试工具 WinDb…