python笔记 多继承下

100 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

0 环境

  • 编辑器:pycharm或者vscode
  • 系统版本:windows10
  • python版本:3.9.6

1 前言

前面提到过了,满足MRO的特性,那么python又是怎么判断它的呢,换句话python怎么判断是否满足条件的呢。这里用到了算法,人称C3算法,或者叫第三算法。

2 参考

看The C3 Method Resolution Order这部分

知乎文章

3 C3算法

类列表

C1 C2 ... CN 表示类列表 [C1 C2 ... CN]

列表头部和尾部

head = C1
tail = C2 ... CN

列表加法

C + (C1 C2 ... CN) = C C1 C2 ... CN 

C3表达式L[C(B1 … BN)] = C + merge(L[B1] … L[BN], B1 … BN),例如: class C: pass,C = [C,O],这里的O是object的意思,假如C(X1...Xn)就等于[C] + merge(mro(X1), ... , mro(Xn), [X1...Xn,O])。这里C3算法,里面的merge算法,它的执行步骤大致如下图:比如F(D,C), D(C), C(O)这种, 1、取第一个列表的首元素,给它一个判断,条件是:在其它的列表中是首元素或在其他列表不存在。满足移除元素,循环遍历,结束标志:直到无法合抛出异常或列表清空为止。

线性化结果+线性化计算: 为了方便,object简化为O。

// 线性化,之前A的mro属性
L[O] = [O]
L[C] = [C, O]
L[D] = [D] + merge(L[C])
L[F] = [F] + merge(L[D] + L[C])
L[F] = [F] + merge([D, C, O], [C, O], [D], [C])
// 按照上面的规则,先拿到D这个元素,挨个判断后面其他列表,存在首元素移除,不存在,下一步循环
L[F] = [F, D] + merge([C, O], [C, O], [C])
L[F] = [F, D, C] + merge([O], [O])
L[F] = [F, D, C, O]

// 假如是F(C,D),首个元素存在,但不在第二个列表的首元素上,相当于F指向C,指定D,然后D指向C。
L[F] = [F] + merge([C, O], [D, C, O], [C], [D])

但是呢,一旦复杂了,上面的方式就会变一变,如下图:顺序A、B、C、D、O。 image.png

补充一点,如果首个列表查找不到好的头,则从第二个列表开始查找好的头,并且移除掉其它列表的元素与该头相同的元素。这里的object我就省略了,类如L[A] = [A] + merge([B,D,E],[C,E,F],[B,C]),第一轮从B,D,E中取出B,满足条件,移除其他列表相应的B以及第一个列表里的B,并且将B合并到MRO中,现在变成了L[A] = [A,B] + merge([D,E],[C,E,F],[C]),假如没有补充这点是不是直接抛异常了,现在D在其它列表中存在且不再首元素,现在取出第二个列表里第一个元素C,满足,去掉相应C,并且将C合并到MRO中,后面循环依次类推,直到所有列表为空。

总结

要满足MRO两个规则,本地优先(继承从左往右)和单调性。子类名(n个父类)相当于子类名加上父类的线性化和父类列表的合并的和。看到合并的过程,也是从左往右开始。还有首个列表取出的元素找不到好头,其他列表存在但不在首位的情况,这块要理解。