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备份Mysql脚本
Aug 11 Python
python操作字典类型的常用方法(推荐)
May 16 Python
python 数据的清理行为实例详解
Jul 12 Python
python3利用smtplib通过qq邮箱发送邮件方法示例
Dec 03 Python
PyQt5实现拖放功能
Apr 25 Python
python+opencv+caffe+摄像头做目标检测的实例代码
Aug 03 Python
python使用pygame框架实现推箱子游戏
Nov 20 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
May 27 Python
keras的backend 设置 tensorflow,theano操作
Jun 30 Python
Python3爬虫中关于中文分词的详解
Jul 29 Python
Python机器学习之基础概述
May 19 Python
关于python中模块和重载的问题
Nov 02 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
基于mysql的论坛(2)
2006/10/09 PHP
PHP生成Flash动画的实现代码
2010/03/12 PHP
PHP防CC攻击实现代码
2011/12/29 PHP
关于PHP内存溢出问题的解决方法
2013/06/25 PHP
php 常用算法和时间复杂度
2013/07/01 PHP
PHP CURL获取返回值的方法
2014/05/04 PHP
基于Laravel实现的用户动态模块开发
2017/09/21 PHP
javascript 模式设计之工厂模式详细说明
2010/05/10 Javascript
js清理Word格式示例代码
2014/02/13 Javascript
JavaScript中的函数声明和函数表达式区别浅析
2015/03/27 Javascript
jquery插件hiAlert实现网页对话框美化
2015/05/03 Javascript
jsp 自动编译机制详细介绍
2016/12/01 Javascript
使用vue.js实现checkbox的全选和多个的删除功能
2017/02/17 Javascript
javascript+html5+css3自定义提示窗口
2017/06/21 Javascript
vue-router 路由基础的详解
2017/10/17 Javascript
jQuery实现模拟搜索引擎的智能提示功能简单示例
2019/01/27 jQuery
JS实现水平遍历和嵌套递归操作示例
2019/08/15 Javascript
Vue实现购物车详情页面的方法
2019/08/20 Javascript
[01:21:58]守擂赛DOTA2第一周决赛
2020/04/22 DOTA
Python中Collection的使用小技巧
2014/08/18 Python
Python中Scrapy爬虫图片处理详解
2017/11/29 Python
Python实现爬取百度贴吧帖子所有楼层图片的爬虫示例
2018/04/26 Python
tensorflow实现图像的裁剪和填充方法
2018/07/27 Python
python3.4控制用户输入与输出的方法
2018/10/17 Python
Python 的AES加密与解密实现
2019/07/09 Python
python3 requests库实现多图片爬取教程
2019/12/18 Python
win10系统下python3安装及pip换源和使用教程
2020/01/06 Python
Python实现一个简单的递归下降分析器
2020/08/01 Python
社区包粽子活动方案
2014/01/21 职场文书
群众路线四风自我剖析材料
2014/10/08 职场文书
检讨书模板
2015/01/29 职场文书
《学会生存》读后感3篇
2019/12/09 职场文书
golang日志包logger的用法详解
2021/05/05 Golang
MySQL分库分表详情
2021/09/25 MySQL
宝塔更新Python及Flask项目的部署
2022/04/11 Python