一、基本概念

1. mro序列

MRO是一个有序列表L,在类被创建时就计算出来。

通用计算公式为:

  1. mro(Child(Base1Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
  2. (其中Child继承自Base1, Base2

如果继承至一个基类:class B(A) 
这时B的mro序列为

  1. mro( B ) = mro( B(A) )
  2. = [B] + merge( mro(A) + [A] )
  3. = [B] + merge( [A] + [A] )
  4. = [B,A]

如果继承至多个基类:class B(A1, A2, A3 …) 
这时B的mro序列

  1. mro(B) = mro( B(A1, A2, A3 …) )
  2. = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
  3. = ...

计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

2. 表头和表尾:

表头: 列表的第一个元素

表尾: 列表中表头以外的元素集合(可以为空)

示例 
列表:[A, B, C] 
表头是A,表尾是B和C

3. 列表之间的+操作

+操作:

  1. [A] + [B] = [A, B]
  2. (以下的计算中默认省略)

3. merge操作:

merge操作流程图:

merge操作示例:

  1. 如计算merge( [E,O], [C,E,F,O], [C] )
  2. 有三个列表
  3.  
  4. 1 merge不为空,取出第一个列表列表①的表头E,进行判断
  5. 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
  6. 2 取出列表②的表头C,进行判断
  7. C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
  8. merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
  9. 3 进行下一次新的merge操作 ......

二、实例

1. 计算实例1

示例:(多继承UML图,引用见参考) 
 
备注:O==object

如何计算mro(A) ?

  1. mro(A) = mro( A(B,C) )
  2.  
  3. 原式= [A] + merge( mro(B),mro(C),[B,C] )
  4.  
  5. mro(B) = mro( B(D,E) )
  6. = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
  7. = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
  8. = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
  9. = [B,D,E] + merge([O] , [O])
  10. = [B,D,E,O]
  11.  
  12. mro(C) = mro( C(E,F) )
  13. = [C] + merge( mro(E), mro(F), [E,F] )
  14. = [C] + merge( [E,O] , [F,O] , [E,F] )
  15. = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
  16. = [C,E,F] + merge([O] , [O])
  17. = [C,E,F,O]
  18.  
  19. 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
  20. = [A,B] + merge( [D,E,O], [C,E,F,O], [C])
  21. = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
  22. = [A,B,D,C] + merge([E,O], [E,F,O])
  23. = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
  24. = [A,B,D,C,E,F] + merge([O], [O])
  25. = [A,B,D,C,E,F,O]

2. 实例代码测试

对于以上计算,用代码来测试。

  1. class D: pass
  2. class E: pass
  3. class F: pass
  4. class B(D,E): pass
  5. class C(E,F): pass
  6. class A(B,C): pass
  7.  
  8. print("从A开始查找:")
  9. for s in A.__mro__:
  10. print(s)
  11.  
  12. print("从B开始查找:")
  13. for s in B.__mro__:
  14. print(s)
  15.  
  16. print("从C开始查找:")
  17. for s in C.__mro__:
  18. print(s)

结果:

  1. A开始查找:
  2. <class '__main__.A'>
  3. <class '__main__.B'>
  4. <class '__main__.D'>
  5. <class '__main__.C'>
  6. <class '__main__.E'>
  7. <class '__main__.F'>
  8. <class 'object'>
  9. B开始查找:
  10. <class '__main__.B'>
  11. <class '__main__.D'>
  12. <class '__main__.E'>
  13. <class 'object'>
  14. C开始查找:
  15. <class '__main__.C'>
  16. <class '__main__.E'>
  17. <class '__main__.F'>
  18. <class 'object'>

三、总结
每次判断如何读取都要这么麻烦计算吗?可有简单方法?
我对此做了一个简单总结。

1. 规律总结
如何快速判断查找规律?

从 “当前子类” 向上查找它的父类,
若 “当前子类” 不是 “查找的父类” 的最后一个继承的子类时,则跳过该 “查找的父类” 的查找,开始查找 “当前子类” 的下一个父类
查找规律流程图:

2. 规律测试

实例2:

对于如下继承: 

通过如下判断模式:

代码测试:

  1. class A1: pass
  2. class A2: pass
  3. class A3: pass
  4. class B1(A1,A2): pass
  5. class B2(A2): pass
  6. class B3(A2,A3): pass
  7. class C1(B1): pass
  8. class C2(B1,B2): pass
  9. class C3(B2,B3): pass
  10. class D(C1, C2, C3): pass
  11.  
  12. print("从D开始查找:")
  13. for s in D.__mro__:
  14. print(s)
  15.  
  16. print("从C3开始查找:")
  17. for s in C3.__mro__:
  18. print(s)

结果:

  1. D开始查找:
  2. <class '__main__.D'>
  3. <class '__main__.C1'>
  4. <class '__main__.C2'>
  5. <class '__main__.B1'>
  6. <class '__main__.A1'>
  7. <class '__main__.C3'>
  8. <class '__main__.B2'>
  9. <class '__main__.B3'>
  10. <class '__main__.A2'>
  11. <class '__main__.A3'>
  12. <class 'object'>
  13. C3开始查找:
  14. <class '__main__.C3'>
  15. <class '__main__.B2'>
  16. <class '__main__.B3'>
  17. <class '__main__.A2'>
  18. <class '__main__.A3'>
  19. <class 'object'>

  

  

  

  

python3的C3算法的更多相关文章

  1. python之路--MRO和C3算法

    一 . MRO(method resolution order) 多继承的一种方法,一种查找的顺序 在python3 里面是一种新类式MRO 需要用都的是C3算法 class A: pass clas ...

  2. python中多继承C3算法研究

    在python的面向对象继承问题中,单继承简单易懂,全部接受传承类的属性,并可添加自带属性, 但是,在多继承情况下,会遇到多个被继承者的顺序问题,以及多次继承后查找前几次继承者需求属性时,可能不易发现 ...

  3. MRO,C3算法

    1了解python2和python3类的区别 python2在2.4之前使用的是经典类, 2.4之后, 使用的是新式类 class Foo: pass class Foo(object): pass ...

  4. python之MRO和C3算法

    python2类和python3类的区别pyhon2中才分新式类与经典类,python3中统一都是新式类Python 2.x中默认都是经典类,只有显式继承了object才是新式类python 3.x中 ...

  5. MRO和C3算法

    本节主要内容: 1.python多继承 2.python经典类的MRO 3.python新式类的MRO,C3算法 4.super() 一.python多继承 在python中类与类之间可以有继承关系, ...

  6. day21 MRO和C3算法

    核能来袭 --MRO和C3算法 1. python的多继承 2.python经典类的MRO 3.python新式类的MRO, C3算法 4.super 是什么鬼? 一.python的多继承 在前面的学 ...

  7. 面向对象多继承(c3算法)、网络基础和编写网络相关的程序

    一.面向对象多继承(c3算法) a.有多个父类先找左,再找右,如下示例: class A(object): pass class B(object): def f1(self): print('B') ...

  8. python MRO及c3算法

    1. 了解python2和python3类的区别 python2在2.3之前使用的是经典类, 2.3之后, 使用的是新式类 2. 经典类的MRO 树形结构的深度优先遍历 -> 树形结构遍历 cl ...

  9. python中的MRO和C3算法

    一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python ...

随机推荐

  1. 和我一起打造个简单搜索之Logstash实时同步建立索引

    用过 Solr 的朋友都知道,Solr 可以直接在配置文件中配置数据库连接从而完成索引的同步创建,但是 ElasticSearch 本身并不具备这样的功能,那如何建立索引呢?方法其实很多,可以使用 J ...

  2. Quartz.NET的简单任务管理类

    昨天使用Quartz.NET做了个定时任务的功能,并实现了多个定时任务的功能 下面这个类实现了如下功能: 1.对定时任务进行管理 2.创建定时任务,需要给定时任务一个job的名称 3.判断给定的job ...

  3. Java基础之基本数据类型

    前言:Java内功心法之基本数据类型,看完这篇你向Java大神的路上又迈出了一步(有什么问题或者需要资料可以联系我的扣扣:734999078) 变量就是申请内存来存储值.也就是说,当创建变量的时候,需 ...

  4. mybatis教程4(动态SQL)

    动态SQL语句 MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空 ...

  5. 如何在framegroup各个frame和window之间共享数据

    可以尝试使用execScript,在指定window或者frame中执行脚本,对于frameGroup里面的frame也有效,若name和frameName都未指定,则在当前window中执行脚本,具 ...

  6. [PHP] 算法-快速排序的PHP实现

    快速排序: 1.基于二分的思想 2.第一个作为基准数,左右各一个指针,同时扫描,右边先走,找到比基准数小的停下 左边再走,找到比基准数大的停下,左右交换 3.当左右相遇的时候,把当前的和基准数调换,递 ...

  7. [PHP] 算法-数组归并排序并计算逆序对的个数的PHP实现

    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%100000000 ...

  8. 8.并发容器ConcurrentHashMap#put方法解析

    jdk1.7.0_79 HashMap可以说是每个Java程序员用的最多的数据结构之一了,无处不见它的身影.关于HashMap,通常也能说出它不是线程安全的.这篇文章要提到的是在多线程并发环境下的Ha ...

  9. API输出的时候是return还是echo?

    写php API写的很少,最近才开始接口的写法,在框架里面一直用return,但是在api中retrun就失效了,为什么呢? 网友给出的答案: 1. return 一般用于函数或方法的返回. echo ...

  10. jQuery点击页面其他部分隐藏下拉菜单

    一.开发小要点 web页面中,我们一般不用select.option来实现下拉菜单效果,因为下拉框的样式丑且难以美化,所以我们选择控制ul显示隐藏来实现同样且高大上的效果,但是不能像下拉框那样点击页面 ...