MRO和C3算法
本节主要内容:
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算法的更多相关文章
- day21 MRO和C3算法
核能来袭 --MRO和C3算法 1. python的多继承 2.python经典类的MRO 3.python新式类的MRO, C3算法 4.super 是什么鬼? 一.python的多继承 在前面的学 ...
- Python的多继承问题-MRO和C3算法
大部分内容转载自C3 线性化算法与 MRO 理解Python中的多继承 Python 中的方法解析顺序(Method Resolution Order, MRO)定义了多继承存在时 Python 解释 ...
- Python之MRO及其C3算法
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>] (<class '__main_ ...
- python全栈开发day103-python垃圾回收机制、mro和c3算法解析、跨域jsonp\CORS、Content-Type组件
Python垃圾回收 -- 引用计数 -- Python为每个对象维护一个引用计数 -- 当引用计数为0的 代表这个对象为垃圾 -- 标记清除 -- 解决孤立的循环引用 -- 标记根节点和可达对象 - ...
- python之路--MRO和C3算法
一 . MRO(method resolution order) 多继承的一种方法,一种查找的顺序 在python3 里面是一种新类式MRO 需要用都的是C3算法 class A: pass clas ...
- python摸爬滚打之day20--多继承,MRO和C3算法
1.新式类和经典类 在python2.2之前, 基类如果不写(), 则表示为经典类; 在python2.2之后, 经典类不复存在, 只存在新式类. 如果基类谁都不继承的话, 则默认继承object. ...
- python之MRO和C3算法
python2类和python3类的区别pyhon2中才分新式类与经典类,python3中统一都是新式类Python 2.x中默认都是经典类,只有显式继承了object才是新式类python 3.x中 ...
- python MRO及c3算法
1. 了解python2和python3类的区别 python2在2.3之前使用的是经典类, 2.3之后, 使用的是新式类 2. 经典类的MRO 树形结构的深度优先遍历 -> 树形结构遍历 cl ...
- python中的MRO和C3算法
一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python ...
随机推荐
- MyBatis学习(一)简单入门程序
MyBatis入门学习 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...
- LCA 最近公共祖先 (模板)
#include <iostream> #include <stdio.h> #include <cstring> #include <vector> ...
- webstorm's interpreter
下载node.js 地址:http://nodejs.cn/ next——> Node interpreter: ……/……/node.exe
- 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 ...
- i2c调试碰到的问题
i2c eeprom i2cget两次结果不一致 i2cset没成功. device里只看到50,却冒出了51地址. i2ctools是针对8bit地址的,而我们的eeprom都是用16bit add ...
- Delphi 如何访问监控摄像头?
源: Delphi 如何访问监控摄像头?
- RTSP 与 RTMP 协议 (转)
源: RTMP协议与RTSP协议比较 RTSP 与 RTMP 协议 RTSP Spec中文版(1-11) RTSP协议 流媒体之rtsp篇 H264视频传输.编解码----RTSP协议
- django 生成动态的PDF文件
需要依赖库. WeasyPrint,它是一个Python库可以生成PDF文件从HTML模板中.安装WeasyPrint pip install WeasyPrint 创建一个PDF模板(templat ...
- Windows下用cmd命令实例讲解yii2.0 的控制台定时任务
Yii中的资源是和Web页面相关的文件,可为CSS文件,JavaScript文件,图片或视频等,资源放在Web可访问的目录下,直接被Web服务器调用. 有时候有些功能需要做到计划任务中去,因此就需要y ...
- 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 ...