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实现协同过滤的教程
Apr 08 Python
详细解析Python当中的数据类型和变量
Apr 25 Python
python判断给定的字符串是否是有效日期的方法
May 13 Python
Python基于SMTP协议实现发送邮件功能详解
Aug 14 Python
Python 打印中文字符的三种方法
Aug 14 Python
解决python3 安装完Pycurl在import pycurl时报错的问题
Oct 15 Python
Python多线程原理与用法实例剖析
Jan 22 Python
Python获取网段内ping通IP的方法
Jan 31 Python
python添加菜单图文讲解
Jun 04 Python
pygame编写音乐播放器的实现代码示例
Nov 19 Python
使用python图形模块turtle库绘制樱花、玫瑰、圣诞树代码实例
Mar 16 Python
详解修改Anaconda中的Jupyter Notebook默认工作路径的三种方式
Jan 24 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
判断Keep-Alive模式的HTTP请求的结束的实现代码
2011/08/06 PHP
PHP 解决session死锁的方法
2013/06/20 PHP
Symfony查询方法实例小结
2017/06/28 PHP
PHP调用微博接口实现微博登录的方法示例
2018/09/22 PHP
addRule在firefox下的兼容写法
2006/11/30 Javascript
判断浏览器的javascript版本的代码
2010/09/03 Javascript
JS构建页面的DOM节点结构的实现代码
2011/12/09 Javascript
extjs 3.31 TreeGrid实现静态页面加载json到TreeGrid里面
2013/04/02 Javascript
jquery submit ie6下失效的原因分析及解决方法
2013/11/15 Javascript
js document.write()使用介绍
2014/02/21 Javascript
js实现图片拖动改变顺序附图
2014/05/13 Javascript
js 判断图片是否加载完以及实现图片的预下载
2014/08/14 Javascript
javascript中setInterval的用法
2015/07/19 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
jquery鼠标悬停导航下划线滑出效果
2017/09/29 jQuery
详解javascript中的变量提升和函数提升
2018/05/24 Javascript
node中间层实现文件上传功能
2018/06/11 Javascript
vue基于better-scroll仿京东分类列表
2020/06/30 Javascript
[04:10]2018年度CS GO玩家最喜爱的主播-完美盛典
2018/12/16 DOTA
[02:23]完美世界全国高校联赛街访DOTA2第一期
2019/11/28 DOTA
python 解析html之BeautifulSoup
2009/07/07 Python
Python去掉字符串中空格的方法
2014/03/11 Python
numpy中的高维数组转置实例
2018/04/17 Python
Python创建普通菜单示例【基于win32ui模块】
2018/05/09 Python
Python Socket编程之多线程聊天室
2018/07/28 Python
Django uwsgi Nginx 的生产环境部署详解
2019/02/02 Python
树莓派动作捕捉抓拍存储图像脚本
2019/06/22 Python
python实现全排列代码(回溯、深度优先搜索)
2020/02/26 Python
CSS3,线性渐变(linear-gradient)的使用总结
2017/01/09 HTML / CSS
美国求婚钻戒网站:Super Jeweler
2016/08/27 全球购物
Yahoo-PHP面试题3
2012/01/14 面试题
如果重写了对象的equals()方法,需要考虑什么
2014/11/02 面试题
清洁工岗位职责
2014/01/29 职场文书
2014年党课学习心得体会
2014/07/08 职场文书
课堂打架检讨书200字
2014/11/21 职场文书
经理聘任证明
2015/03/02 职场文书