python多重继承新算法C3介绍


Posted in Python onSeptember 28, 2014

mro即 method resolution order (方法解释顺序),主要用于在多继承时判断属性的路径(来自于哪个类)。

在python2.2版本中,算法基本思想是根据每个祖先类的继承结构,编译出一张列表,包括搜索到的类,按策略删除重复的。但是,在维护单调性方面失败过(顺序保存),所以从2.3版本,采用了新算法C3。

为什么采用C3算法

C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。

单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序。

C3算法

判断mro要先确定一个线性序列,然后查找路径由由序列中类的顺序决定。所以C3算法就是生成一个线性序列。

如果继承至一个基类:

class B(A)

这时B的mro序列为[B,A]

如果继承至多个基类

class B(A1,A2,A3 ...)

这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])
merge操作就是C3算法的核心。

遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。

merge操作后的序列,继续执行merge操作,直到merge操作的序列为空。

如果merge操作的序列无法为空,则说明不合法。

例子:

class A(O):pass

class B(O):pass

class C(O):pass

class E(A,B):pass

class F(B,C):pass

class G(E,F):pass

A、B、C都继承至一个基类,所以mro序列依次为[A,O]、[B,O]、[C,O]

mro(E) = [E] + merge(mro(A), mro(B), [A,B])

       = [E] + merge([A,O], [B,O], [A,B])

执行merge操作的序列为[A,O]、[B,O]、[A,B]

A是序列[A,O]中的第一个元素,在序列[B,O]中不出现,在序列[A,B]中也是第一个元素,所以从执行merge操作的序列([A,O]、[B,O]、[A,B])中删除A,合并到当前mro,[E]中。
mro(E) = [E,A] + merge([O], [B,O], [B])

再执行merge操作,O是序列[O]中的第一个元素,但O在序列[B,O]中出现并且不是其中第一个元素。继续查看[B,O]的第一个元素B,B满足条件,所以从执行merge操作的序列中删除B,合并到[E, A]中。

mro(E) = [E,A,B] + merge([O], [O])

       = [E,A,B,O]

实现C3算法的代码

#-*- encoding:GBK -*-#  

def mro_C3(*cls):  

        if len(cls)==1:  

            if not cls[0].__bases__:  

                return  cls  

            else:  

                return cls+ mro_C3(*cls[0].__bases__)  

        else:  

            seqs = [list(mro_C3(C)) for C in cls ] +[list(cls)]  

            res = []  

            while True:  

              non_empty = list(filter(None, seqs))  

              if not non_empty:  

                  return tuple(res)  

              for seq in non_empty:  

                  candidate = seq[0]  

                  not_head = [s for s in non_empty if candidate in s[1:]]  

                  if not_head:  

                      candidate = None  

                  else:  

                      break  

              if not candidate:  

                  raise TypeError("inconsistent hierarchy, no C3 MRO is possible")  

              res.append(candidate)  

              for seq in non_empty:  

                  if seq[0] == candidate:  

                      del seq[0]

Python 相关文章推荐
举例讲解Python中的身份运算符的使用方法
Oct 13 Python
总结网络IO模型与select模型的Python实例讲解
Jun 27 Python
python+selenium实现163邮箱自动登陆的方法
Dec 31 Python
利用pandas将numpy数组导出生成excel的实例
Jun 14 Python
Scrapy框架使用的基本知识
Oct 21 Python
Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解
Feb 28 Python
详解python中sort排序使用
Mar 23 Python
Python Web程序搭建简单的Web服务器
Jul 31 Python
如何将tensorflow训练好的模型移植到Android (MNIST手写数字识别)
Apr 22 Python
python进行参数传递的方法
May 12 Python
Django Form常用功能及代码示例
Oct 13 Python
Python实现石头剪刀布游戏
Jan 20 Python
wxPython窗口的继承机制实例分析
Sep 28 #Python
wxPython框架类和面板类的使用实例
Sep 28 #Python
Python的加密模块md5、sha、crypt使用实例
Sep 28 #Python
wxPython学习之主框架实例
Sep 28 #Python
python实现得到一个给定类的虚函数
Sep 28 #Python
python实现根据图标提取分类应用程序实例
Sep 28 #Python
wxPython事件驱动实例详解
Sep 28 #Python
You might like
Linux下快速搭建php开发环境
2017/03/13 PHP
PHP数组中头部和尾部添加元素的方法(array_unshift,array_push)
2017/04/10 PHP
PHP实现网页内容html标签补全和过滤的方法小结【2种方法】
2017/04/27 PHP
基于jQuery图片平滑连续滚动插件
2009/04/27 Javascript
jQuery对象和DOM对象使用说明
2010/06/25 Javascript
JS无法捕获滚动条上的mouse up事件的原因猜想
2012/03/21 Javascript
jQuery(非HTML5)可编辑表格实现代码
2012/12/11 Javascript
从JQuery源码分析JavaScript函数的apply方法与call方法
2014/09/25 Javascript
js实现类似MSN提示的页面效果代码分享
2015/08/24 Javascript
JS实现选中当前菜单后高亮显示的导航条效果
2015/10/15 Javascript
轻量级jQuery插件slideBox实现带底栏轮播(焦点图)代码
2016/03/28 Javascript
结合代码图文讲解JavaScript中的作用域与作用域链
2016/07/05 Javascript
Javascript json object 与string 相互转换的简单实现
2016/09/27 Javascript
基于Node.js + WebSocket打造即时聊天程序嗨聊
2016/11/29 Javascript
浅谈vue-cli加载不到dev-server.js的解决办法
2017/11/24 Javascript
Javascript三种字符串连接方式及性能比较
2019/05/28 Javascript
在React中写一个Animation组件为组件进入和离开加上动画/过度效果
2019/06/24 Javascript
基于JavaScript实现表格隔行换色
2020/05/08 Javascript
uni-app 自定义底部导航栏的实现
2020/12/11 Javascript
python创建进程fork用法
2015/06/04 Python
Python采用Django开发自己的博客系统
2020/09/29 Python
用python实现百度翻译的示例代码
2018/03/09 Python
pytorch多GPU并行运算的实现
2019/09/27 Python
浅谈在django中使用filter()(即对QuerySet操作)时踩的坑
2020/03/31 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
Selenium常见异常解析及解决方案示范
2020/04/10 Python
Python pymsql模块的使用
2020/09/07 Python
Python爬虫scrapy框架Cookie池(微博Cookie池)的使用
2021/01/13 Python
优秀大学生的自我评价
2014/01/16 职场文书
新学期标语
2014/06/30 职场文书
学子宴致辞大全
2015/07/27 职场文书
Go 在 MongoDB 中常用查询与修改的操作
2021/05/07 Golang
利用python Pandas实现批量拆分Excel与合并Excel
2021/05/23 Python
浅谈Python魔法方法
2021/06/28 Java/Android
利用js实现简单开关灯代码
2021/11/23 Javascript
Spring依赖注入多种类型数据的示例代码
2022/03/31 Java/Android