python多重继承新算法C3介绍

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]

(0)

相关推荐

  • python的多重继承的理解

    python的多重继承的理解 Python和C++一样,支持多继承.概念虽然容易,但是困难的工作是如果子类调用一个自身没有定义的属性,它是按照何种顺序去到父类寻找呢,尤其是众多父类中有多个都包含该同名属性. 对经典类和新式类来说,属性的查找顺序是不同的.现在我们分别看一下经典类和新式类两种不同的表现: 经典类: #! /usr/bin/python # -*- coding:utf-8 -*- class P1(): def foo(self): print 'p1-foo' class P2(

  • Python类的多重继承问题深入分析

    正文 首先得说明的是,Python的类分为经典类 和 新式类 经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了 新式类在python2.2之后的版本中都可以使用 经典类和新式类的区别在于: 经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的: 复制代码 代码如下: # old style class A():pass # new style class A(obejct):pass 2.经典类在类多重继承的时候是采用从左到右

  • 浅析Python中的多重继承

    继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能. 回忆一下Animal类层次的设计,假设我们要实现以下4种动物: Dog - 狗狗: Bat - 蝙蝠: Parrot - 鹦鹉: Ostrich - 鸵鸟. 如果按照哺乳动物和鸟类归类,我们可以设计出这样的类的层次: 但是如果按照"能跑"和"能飞"来归类,我们就应该设计出这样的类的层次: 如果要把上面的两种分类都包含进来,我们就得设计更多的层次: 哺乳类:能跑的哺乳类,能飞的哺乳类: 鸟类

  • python多重继承实例

    本文实例讲述了python多重继承用法,分享给大家供大家参考.具体实现方法如下: 1.mro.py文件如下: #!/usr/bin/python # Filename:mro.py class P1: def foo(self): print 'called P1-foo' class P2: def foo(self): print 'called P2-foo' def bar(self): print 'called P2-bar' class C1(P1, P2): pass class

  • python多重继承新算法C3介绍

    mro即 method resolution order (方法解释顺序),主要用于在多继承时判断属性的路径(来自于哪个类). 在python2.2版本中,算法基本思想是根据每个祖先类的继承结构,编译出一张列表,包括搜索到的类,按策略删除重复的.但是,在维护单调性方面失败过(顺序保存),所以从2.3版本,采用了新算法C3. 为什么采用C3算法 C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题. 本地优先级:指声明时父类的顺

  • Python多重继承之菱形继承的实例详解

    继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能.在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance ). 语法 class SubclassName(BaseClass1, BaseClass2, BaseClass3, ...): pass 菱形继承 在多层继承和多继承同时使用的情况下,就会出现复杂的继承关系,多重多继承. 其中,就会出现菱形继承.如下图所示.mark 在这种结构中,在调用顺序上就出现了疑惑

  • python实现聚类算法原理

    本文主要内容: 聚类算法的特点 聚类算法样本间的属性(包括,有序属性.无序属性)度量标准 聚类的常见算法,原型聚类(主要论述K均值聚类),层次聚类.密度聚类 K均值聚类算法的python实现,以及聚类算法与EM最大算法的关系 参考引用 先上一张gif的k均值聚类算法动态图片,让大家对算法有个感性认识: 其中:N=200代表有200个样本,不同的颜色代表不同的簇(其中 3种颜色为3个簇),星星代表每个簇的簇心.算法通过25次迭代找到收敛的簇心,以及对应的簇. 每次迭代的过程中,簇心和对应的簇都在变

  • Python数据结构与算法(几种排序)小结

    Python数据结构与算法(几种排序) 数据结构与算法(Python) 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 冒泡排序算法的运作如下: 比较相邻的元素.如果第一个比第二个大(升序),就交换他们两个. 对每一对相邻元素作同样的工作,从

  • 基于python实现雪花算法过程详解

    这篇文章主要介绍了基于python实现雪花算法过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Snowflake是Twitter提出来的一个算法,其目的是生成一个64bit的整数: 1bit:一般是符号位,不做处理 41bit:用来记录时间戳,这里可以记录69年,如果设置好起始时间比如今年是2018年,那么可以用到2089年,到时候怎么办?要是这个系统能用69年,我相信这个系统早都重构了好多次了. 10bit:10bit用来记录机器ID

  • python K近邻算法的kd树实现

    k近邻算法的介绍 k近邻算法是一种基本的分类和回归方法,这里只实现分类的k近邻算法. k近邻算法的输入为实例的特征向量,对应特征空间的点:输出为实例的类别,可以取多类. k近邻算法不具有显式的学习过程,实际上k近邻算法是利用训练数据集对特征向量空间进行划分.将划分的空间模型作为其分类模型. k近邻算法的三要素 k值的选择:即分类决策时选择k个最近邻实例: 距离度量:即预测实例点和训练实例点间的距离,一般使用L2距离即欧氏距离: 分类决策规则. 下面对三要素进行一下说明: 1.欧氏距离即欧几里得距

  • python扫描线填充算法详解

    本文实例为大家分享了python扫描线填充算法,供大家参考,具体内容如下 介绍 1.用水平扫描线从上到下扫描由点线段构成的多段构成的多边形. 2.每根扫描线与多边形各边产生一系列交点.将这些交点按照x坐标进行分类,将分类后的交点成对取出,作为两个端点,以所填的色彩画水平直线. 3.多边形被扫描完毕后,填色也就完成. 数据结构 活性边表: 新边表: 代码(使用数组) import numpy as np from PIL import Image from PIL import ImageDraw

  • 详解python 支持向量机(SVM)算法

    相比于逻辑回归,在很多情况下,SVM算法能够对数据计算从而产生更好的精度.而传统的SVM只能适用于二分类操作,不过却可以通过核技巧(核函数),使得SVM可以应用于多分类的任务中. 本篇文章只是介绍SVM的原理以及核技巧究竟是怎么一回事,最后会介绍sklearn svm各个参数作用和一个demo实战的内容,尽量通俗易懂.至于公式推导方面,网上关于这方面的文章太多了,这里就不多进行展开了~ 1.SVM简介 支持向量机,能在N维平面中,找到最明显得对数据进行分类的一个超平面!看下面这幅图: 如上图中,

  • python利用K-Means算法实现对数据的聚类案例详解

    目的是为了检测出采集数据中的异常值.所以很明确,这种情况下的簇为2:正常数据和异常数据两大类 1.安装相应的库 import matplotlib.pyplot as plt # 用于可视化 from sklearn.cluster import KMeans # 用于聚类 import pandas as pd # 用于读取文件 2.实现聚类 2.1 读取数据并可视化 # 读取本地数据文件 df = pd.read_excel("../data/output3.xls", heade

  • python入门之算法学习

    前言 参考学习书籍:<算法图解>[美]Aditya Bhargava,袁国忠(译)北京人民邮电出版社,2017 二分查找 binary_search 实现二分查找的python代码如下: def binary_search(list, item): low = 0 #最低位索引位置为0 high = len(list)- 1 #最高位索引位置为总长度-1 while low <= high: mid = (low + high)//2 #检查中间的元素,书上是一条斜杠,我试过加两条斜杠才

随机推荐