本节主要内容:

1.python多继承

2.python经典类的MRO

3.python新式类的MRO,C3算法

4.super()

一.python多继承

在python中类与类之间可以有继承关系,这也是面向对象的一大特征之一.

在继承关系中,子类自动拥有父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类.

  1. class Shen:
  2. def fly(self):
  3. print("大神会飞")
  4. class Hou:
  5. def chi(self):
  6. print("猴子吃桃子")
  7.  
  8. class SunWuKong(Shen, Hou): # 一个类可以继承多个无关的类. 一个类可以被多个无关的类继承
  9. pass
  10.  
  11. class TaiShangLaoJun(Shen):
  12. pass
  13.  
  14. swk = SunWuKong()
  15. swk.fly()
  16. swk.chi()

此时,孙悟空是一只猴子,同时也是一个神仙.那孙悟空继承了这两个类.孙悟空自然就可以执行这两个类的方法.

在多继承中存在着这样一个问题.当两个父类中出现了重名方法的时候.该执行哪一个呢?这时就设计到如何查找父类方法的

这么一个问题.即MRO(method resolution order)问题. 在python中这时一个很复杂的问题.因为在不同的python版本中使用的

是不同的算法来完成MRO的.首先,我们目前能见到的两个版本:

·python2

在python2中存在两种类.

一个叫经典类.在python2.2之前使用的是经典类.经典类在基类的根如果什么都不写,表示继承xxx.

一个叫新式类.在python2.2之后出现了新式类.新式类的特点是基类的根是object

·python

python3中使用的都是新式类,如果基类谁都不继承,那这个类会默认继承object

二.经典类的MRO

经典类的MRO是通过树形结构的深度优先遍历.

在python的继承体系中,我们可以把类与类继承关系化成一个树形结构的图.

  1. class A:
  2. pass
  3.  
  4. class B(A):
  5. pass
  6.  
  7. class C(A):
  8. pass
  9.  
  10. class D(B, C):
  11. pass
  12.  
  13. class E:
  14. pass
  15.  
  16. class F(D, E):
  17. pass
  18.  
  19. class G(F, D):
  20. pass
  21.  
  22. class H:
  23. pass
  24.  
  25. class Foo(H, G):
  26. pass

对付这样的MRO.很简单.画图即可:

继承关系图已经有了.那如何进行查找呢?记住一个原则.在经典类中采用的是树形深度优先遍历方案.就是从下往上,从左子树

到右子树,一条路走到头.

所以上面的类的MRO为:Foo->H->G->F->D->B->A->C->E

三.新式类的MRO

python中的新式类的MRO采用的是C3算法来完成的.

C3算法不需要画图,我们只要看代码就可以了:

  1. class A:
  2. pass
  3. class B(A):
  4. pass
  5. class C(A):
  6. pass
  7. class D(B, C):
  8. pass
  9. class E(C, A):
  10. pass
  11. class F(D, E):
  12. pass
  13. class M(F, E):
  14. pass
  15. class N:
  16. pass
  17. class P(M,N):
  18. pass
  19. class G(P):
  20. pass
  21. class O:
  22. pass
  23. class H(G, F):
  24. pass

首先.我们要确定从H开始找,也就是说.创建的是H的对象.

如果从H找,那找到H+H的父类的C3,我们设C3算法是L(x),即给出x类.找到的MRO

L(H) = H + L(G) + L(F) + (G,F)

继续从代码中找G和F的父类往里面代

L(G) = G + L(E) +  (E,)

L(F) = F + L(D)+ L(E) + (D,E)

继续找E 和 D

L(E) = E + L(C) + L(A) +(C,A)

L(D) = D + L(B) + L(C) + (B,C)

继续找B和C

L(B) = B + L(A) +  (A,)

L(C) = C + L(A) + (A,)

最后就剩下一个A了,因为A没有父类所以不用再找了.接下来把L(A)往里面代,再推回去,但要记住,

这里的+表示的是merge.merge的原则是用每个院的头一项和后面元组的除头一项外的其他元素

进行比较,看是否存在.如果存在,就从下一个元组的头一项继续找,如果找不到,就拿出来.作为merge

的结果的一项.以此类推,直到元组之间的元素都相同了,也就不用再找了.

L(B) =(B,) + (A,) +(A,) -> (B, A)

L(C) =(C,) + (A,) + (A,) -> (C, A)

L(E) = (E,) + (C, A) + (A) +(C,A)  -> E, C, A

L(D) = (D,) + (B, A) + (C, A) + (B,C)  -> D, B, A

L(G) = (G,) + (E, C, A) -> G, E, C, A

L(F) = (F,) + (D, B, A) + (E, C, A) + (D,E) -> F,  D, B,  E, C, A

L(H) = (H, ) + (G, E, C, A) + ( F,  D,  B,  E, C, A) + (G,F)-> H, G, F, D, B, E, C, A

最终的结果是HGFDBECA,那如何验证?其实python中可以使用类名.__mro__获取到类的MRO信息.

  1. print(H.__mro__)
  2. # 结果:
  3. # (<class '__main__.Foo'>, <class '__main__.H'>, <class '__main__.G'>, <class '__main__.F'>,
  4. # <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>,
  5. # <class '__main__.E'>, <class 'object'>)

C3是把我们多个类产生的共同继承留到最后去找,所以,我们也可以从图上来看到相关的规律.这个要多写多画图

才能感觉到.但是如果没有所谓的共同继承关系,那就几乎就当成深度遍历就可以了.

以下是python官网关于MRO C3算法的文档地址:

https://www.python.org/download/releases/2.3/mro/

四.super()

super()可以帮助我们执行MRO中下一个父类的方法.通常super()有两个使用的地方:

1.可以访问父类的构造方法

2.当子类方法想调用父类(MRO)中的方法

先看第一种情况:

  1. class Foo:
  2. def __init__(self,a,b,c):
  3. self.a = a
  4. self.b = b
  5. self.c = c
  6.  
  7. class Bar(Foo):
  8. def __init__(self,a,b,c,d):
  9. super(Bar, self).__init__(a,b,c)
  10. self.d = d
  11.  
  12. b = Bar(1,2,3,4)
  13. print(b.__dict__)
  14.  
  15. # 结果:
  16. # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

这样我们就不需要写这么多代码,直接到父类的构造帮我们完成一部分代码

第二种:

  1. class ShengWu:
  2. def dong(self): # 实例方法
  3. print(self)
  4. print("我是生物")
  5.  
  6. class Animal(ShengWu):
  7. def dong(self):
  8. print("我是动物")
  9. class Cat(Animal):
  10. def dong(self): # 子类中出现了和父类重名的内容. 表示对父类的方法的覆盖(重写). 半盖(java)
  11. super(Cat, self).dong()
  12. # super(Animal, self).dong() # 定位到Animal. 找Animal的下一个
  13. # super(类, 对象).方法() 找到MRO中的类. 找这个类的下一个. 去执行方法
  14. print("我的猫也会动")

最后是一个面试题:

  1. # MRO + super ⾯试题
  2. class Init(object):
  3. def __init__(self, v):
  4. print("init")
  5. self.val = v #
  6. class Add2(Init):
  7. def __init__(self, val): #
  8. print("Add2")
  9. super(Add2, self).__init__(val)
  10. print(self.val) # 5.0
  11. self.val += 2 # 7.0
  12. class Mult(Init):
  13. def __init__(self, val):
  14. print("Mult")
  15. super(Mult, self).__init__(val)
  16. self.val *= 5 # 5.0
  17. class HaHa(Init):
  18. def __init__(self, val):
  19. print("哈哈")
  20. super(HaHa, self).__init__(val)
  21. self.val /= 5 # 1.0
  22. class Pro(Add2,Mult,HaHa): #
  23. pass
  24. class Incr(Pro):
  25. def __init__(self, val): #
  26. super(Incr, self).__init__(val)
  27. self.val += 1 # 8.0
  28.  
  29. # Incr, pro, add2, mult, haha, Init
  30. p = Incr(5)
  31. print(p.val) # ?
  32. # Add2 init
  33. c = Add2(2)
  34. print(c.val) # ?
  35. # 结果:
  36. '''
  37. add2
  38. Mult
  39. 哈哈
  40. init
  41. 5.0
  42. 8.0
  43. Add2
  44. init
  45. 2
  46. 4
  47.  
  48. '''

MRO和C3算法的更多相关文章

  1. day21 MRO和C3算法

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

  2. Python的多继承问题-MRO和C3算法

    大部分内容转载自C3 线性化算法与 MRO 理解Python中的多继承 Python 中的方法解析顺序(Method Resolution Order, MRO)定义了多继承存在时 Python 解释 ...

  3. Python之MRO及其C3算法

    [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>] (<class '__main_ ...

  4. python全栈开发day103-python垃圾回收机制、mro和c3算法解析、跨域jsonp\CORS、Content-Type组件

    Python垃圾回收 -- 引用计数 -- Python为每个对象维护一个引用计数 -- 当引用计数为0的 代表这个对象为垃圾 -- 标记清除 -- 解决孤立的循环引用 -- 标记根节点和可达对象 - ...

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

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

  6. python摸爬滚打之day20--多继承,MRO和C3算法

    1.新式类和经典类 在python2.2之前, 基类如果不写(), 则表示为经典类; 在python2.2之后, 经典类不复存在, 只存在新式类. 如果基类谁都不继承的话, 则默认继承object. ...

  7. python之MRO和C3算法

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

  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. Set接口——HashSet集合

    不重复,无索引,不能重复元素,没有索引: HashSet集合: 此时实现Set接口,有哈希表(HashMap的一个实例)支持,哈希表意味着查询速度很快, 是无序的,即元素的存取的顺序可能不一致: 且此 ...

  2. Java 高级开发必修知识---内部类

    摘自:http://www.cnblogs.com/lsy131479/p/8798912.html Java 内部类分为: 1)成员内部类 2)静态嵌套类 3)方法内部类 4)匿名内部类 内部类的共 ...

  3. AngularJS之登录显示用户名

    效果图:在这里会显示出来用户名 使用AngularJs进行这样效果 第一步:写ng-app // 定义模块: var app = angular.module("pinyougou" ...

  4. 登陆 全站 user

    TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join( ...

  5. percona-server-5.7.18-14安装

    说明 percona-server-5.7 的安装对硬件配置的要求较高,至少需要4G内存或者2G物理内存+2Gswap. 编译安装过程中注意所在分区的空间大小,编译安装需要使用到大量的临时空间. 环境 ...

  6. Prometheus监控学习笔记之教程推荐

    最近学习K8S和基于容器的监控,发现了如下的教程质量不错,记录下来以备参考 1. K8S最佳实战(包括了K8S的Prometheus监控和EFK日志搜集) https://jimmysong.io/k ...

  7. python使用super()调用父类的方法

    如果要在子类中引用父类的方法,但是又需要添加一些子类所特有的内容,可通过类名.方法()和super()来调用父类的方法,再个性化子类的对应函数. 直接使用类名.方法()来调用时,还是需要传入self为 ...

  8. The Architecture of Open Source Applications: Berkeley DB

    最近研究内存关系数据库的设计与实现,下面一篇为berkeley db原始两位作为的Berkeley DB设计回忆录: Conway's Law states that a design reflect ...

  9. vs变量监视提示-VAR-CREATE: UNABLE TO CREATE VARIABLE OBJECT解决方法

    昨天有个linux应用在使用vs 远程debug的时候,debug可以正常进行,但是监视变量的时候提示-VAR-CREATE: UNABLE TO CREATE VARIABLE OBJECT,经测试 ...

  10. [ERROR] InnoDB: Trying to access page number 7 in space 957, space name XXX which is outside the tablespace bounds

    早上,测试说演示环境mysql老实断开重连,一update就挂,经查日志,有如下异常: 2017-04-05T23:13:01.729250+08:00 17065 [ERROR] InnoDB: T ...