本节主要内容:

1.python多继承

2.python经典类的MRO

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

4.super()

一.python多继承

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

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

class Shen:
def fly(self):
print("大神会飞")
class Hou:
def chi(self):
print("猴子吃桃子") class SunWuKong(Shen, Hou): # 一个类可以继承多个无关的类. 一个类可以被多个无关的类继承
pass class TaiShangLaoJun(Shen):
pass swk = SunWuKong()
swk.fly()
swk.chi()

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

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

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

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

·python2

在python2中存在两种类.

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

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

·python

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

二.经典类的MRO

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

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

class A:
pass class B(A):
pass class C(A):
pass class D(B, C):
pass class E:
pass class F(D, E):
pass class G(F, D):
pass class H:
pass class Foo(H, G):
pass

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

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

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

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

三.新式类的MRO

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

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

class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E(C, A):
pass
class F(D, E):
pass
class M(F, E):
pass
class N:
pass
class P(M,N):
pass
class G(P):
pass
class O:
pass
class H(G, F):
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信息.

print(H.__mro__)
# 结果:
# (<class '__main__.Foo'>, <class '__main__.H'>, <class '__main__.G'>, <class '__main__.F'>,
# <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>,
# <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)中的方法

先看第一种情况:

class Foo:
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c class Bar(Foo):
def __init__(self,a,b,c,d):
super(Bar, self).__init__(a,b,c)
self.d = d b = Bar(1,2,3,4)
print(b.__dict__) # 结果:
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}

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

第二种:

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

最后是一个面试题:

# MRO + super ⾯试题
class Init(object):
def __init__(self, v):
print("init")
self.val = v #
class Add2(Init):
def __init__(self, val): #
print("Add2")
super(Add2, self).__init__(val)
print(self.val) # 5.0
self.val += 2 # 7.0
class Mult(Init):
def __init__(self, val):
print("Mult")
super(Mult, self).__init__(val)
self.val *= 5 # 5.0
class HaHa(Init):
def __init__(self, val):
print("哈哈")
super(HaHa, self).__init__(val)
self.val /= 5 # 1.0
class Pro(Add2,Mult,HaHa): #
pass
class Incr(Pro):
def __init__(self, val): #
super(Incr, self).__init__(val)
self.val += 1 # 8.0 # Incr, pro, add2, mult, haha, Init
p = Incr(5)
print(p.val) # ?
# Add2 init
c = Add2(2)
print(c.val) # ?
# 结果:
'''
add2
Mult
哈哈
init
5.0
8.0
Add2
init
2
4 '''

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. MyBatis学习(一)简单入门程序

    MyBatis入门学习 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...

  2. LCA 最近公共祖先 (模板)

    #include <iostream> #include <stdio.h> #include <cstring> #include <vector> ...

  3. webstorm's interpreter

    下载node.js 地址:http://nodejs.cn/ next——> Node interpreter: ……/……/node.exe

  4. The Little Prince-12/04

    The Little Prince-12/04 The wheat fields have nothing to say to me. And that is sad. But you have ha ...

  5. i2c调试碰到的问题

    i2c eeprom i2cget两次结果不一致 i2cset没成功. device里只看到50,却冒出了51地址. i2ctools是针对8bit地址的,而我们的eeprom都是用16bit add ...

  6. Delphi 如何访问监控摄像头?

    源: Delphi 如何访问监控摄像头?

  7. RTSP 与 RTMP 协议 (转)

    源: RTMP协议与RTSP协议比较 RTSP 与 RTMP 协议 RTSP Spec中文版(1-11) RTSP协议 流媒体之rtsp篇 H264视频传输.编解码----RTSP协议

  8. django 生成动态的PDF文件

    需要依赖库. WeasyPrint,它是一个Python库可以生成PDF文件从HTML模板中.安装WeasyPrint pip install WeasyPrint 创建一个PDF模板(templat ...

  9. Windows下用cmd命令实例讲解yii2.0 的控制台定时任务

    Yii中的资源是和Web页面相关的文件,可为CSS文件,JavaScript文件,图片或视频等,资源放在Web可访问的目录下,直接被Web服务器调用. 有时候有些功能需要做到计划任务中去,因此就需要y ...

  10. git clone 报错Unable to negotiate with xxx.xxx.xxx.xxx port 12345: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1

    在执行git clone命令报错 Unable to negotiate with xxx.xxx.xxx.xxx port 12345: no matching key exchange metho ...