多继承的实现

class A(object):def out(self):print("A类方法")class B(object):def out(self):print("B类方法")class C(A, B):passc = C()
# 打印C类的调用路径顺序(注意要类名.__mro__)
print(C.__mro__)
c.out()

运行结果:

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
A类方法

可以尝试一下把 C类 的继承顺序改成 B,A

class C(B, A):pass

结果就是

(<class ‘main.C’>, <class ‘main.B’>, <class ‘object’>, <class ‘main.A’>)
B类方法

如果 C类out() 方法重写那么将执行 C类的 out() 方法

class C(B, A):def out(self):print("C类方法")

结果如下:

(<class ‘main.C’>, <class ‘main.B’>, <class ‘object’>, <class ‘main.A’>)
C类方法

了解MRO

新式类可以直接通过 类名.__mro__ 的方式获取类的 MRO,也可以通过 类名.mro() 的形式,旧式类是没有 mro 属性和 mro() 方法的。

方法解析顺序 Method Resolution Order,简称 MRO。主要用于在多继承时判断方法,属性的调用路径。

  • 在搜索方法时,是按照 mro() 输出的结果,从左到右的顺序查找的
  • 如果找到,在当前类中找到方法就直接执行,不在搜索
  • 没有找到,就依次查找下一个类中是否有对应的方法,找到执行,不在搜索
  • 如果最后一个类,还没有找到方法,程序报错

MRO 的顺序是根据 Python中C3算法 得来的大家感兴趣可以去研究一下,这里就不在赘述了。

新式类和旧式类

在早期版本的 Python 中,所有类并没有一个共同的祖先 object,如果定义一个类,但没有显式指定其祖先,那么就被解释为 旧式类,例如:

class oldA:  passclass oldB:pass

其中,oldAoldB 都属于旧式类

Python 2.x 版本中,为了向后兼容保留了旧式类。该版本中的 新式类必须 显式继承 object 或者其他新式类:

class NewA(object):  passclass NewB(NewA):  pass

显然,以上两个类都属于 新式类

而在 Python 3.x 版本中,不再保留旧式类的概念。因此,没有继承任何其他类的类都隐式地继承自 object

super()的使用

super() 函数是用于调用父类(超类)的一个方法。

super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

单继承

父类名调用

"""
单继承使用父类名调用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")Parent.eat(self)print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")Parent.eat(self)print("\tson2  ---  爱吃水果\n")def main():s1 = Son1()s2 = Son2()s1.eat()s2.eat()if __name__ == '__main__':main()

运行结果

son1 --- eat()parent --- 爱吃饭son1  ---  爱吃蔬菜son2 --- eat()parent --- 爱吃饭son2  ---  爱吃水果

使用super()

"""
单继承中super()的使用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")super().eat()print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")super().eat()print("\tson2  ---  爱吃水果\n")def main():s1 = Son1()s2 = Son2()s1.eat()s2.eat()if __name__ == '__main__':main()

运行结果:

son1 --- eat()parent --- 爱吃饭son1  ---  爱吃蔬菜son2 --- eat()parent --- 爱吃饭son2  ---  爱吃水果

可以发现在单继承使用 父类名super() 调用父类方法结果都一样。

多继承

还是上面例子,就是加一个 GrandSon 类,让它继承 Son1, Son2 。让 eat() 具备其父类的特性。

父类名调用

"""
多继承中父类名的使用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")Parent.eat(self)print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")Parent.eat(self)print("\tson2  ---  爱吃水果\n")class Grandson(Son1, Son2):def eat(self):print("grandson --- eat()")# super().eat()Son1.eat(self)Son2.eat(self)print("\tgrandson --- 爱吃零食")def main():# s1 = Son1()# s2 = Son2()# s1.eat()# s2.eat()g = Grandson()g.eat()if __name__ == '__main__':main()

运行结果

grandson --- eat()
son1 --- eat()parent --- 爱吃饭son1  ---  爱吃蔬菜son2 --- eat()parent --- 爱吃饭son2  ---  爱吃水果grandson --- 爱吃零食

结果显示 Parenteat() 方法调用了多次,存在重复调用。

使用super()

"""
多继承中super()的使用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")super().eat()print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")super().eat()print("\tson2  ---  爱吃水果\n")class Grandson(Son1, Son2):def eat(self):print("grandson --- eat()")super().eat()print("\tgrandson --- 爱吃零食")def main():g = Grandson()g.eat()if __name__ == '__main__':main()

运行结果

grandson --- eat()
son1 --- eat()
son2 --- eat()parent --- 爱吃饭son2  ---  爱吃水果son1  ---  爱吃蔬菜grandson --- 爱吃零食

可以发现在多继承中使用 super() 没有重复调用。

假如在多继承中 Grandson 类的 eat() 方法只想复用 Parent, Son1eat()的方法,不需要 Son2的。该如何实现呢?

父类名调用

"""
父类名的使用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")Parent.eat(self)print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")Parent.eat(self)print("\tson2  ---  爱吃水果\n")class Grandson(Son1, Son2):def eat(self):print("grandson --- eat()")Son1.eat(self)# Son2.eat(self)print("\tgrandson --- 爱吃零食")def main():print(Grandson.mro())g = Grandson()g.eat()if __name__ == '__main__':main()

结果如下

[<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>
]grandson --- eat()
son1 --- eat()parent --- 爱吃饭son1  ---  爱吃蔬菜grandson --- 爱吃零食
[Finished in 0.1s]

super()调用

"""
super()的使用
"""class Parent(object):def eat(self):print("\tparent --- 爱吃饭")class Son1(Parent):def eat(self):print("son1 --- eat()")super().eat()print("\tson1  ---  爱吃蔬菜\n")class Son2(Parent):def eat(self):print("son2 --- eat()")super().eat()print("\tson2  ---  爱吃水果\n")class Grandson(Son1, Son2):def eat(self):print("grandson --- eat()")super(Son1, self).eat()# Son1.eat(self)# Son2.eat(self)print("\tgrandson --- 爱吃零食")def main():print(Grandson.mro())g = Grandson()g.eat()if __name__ == '__main__':main()

结果如下

[<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>
]grandson --- eat()
son2 --- eat()parent --- 爱吃饭son2  ---  爱吃水果grandson --- 爱吃零食
[Finished in 0.1s]

然而却发现 super(Son1, self).eat() 调用的是 Son2eat() 方法。

是因为 MRO 的原因,当调用 super(Son1,self).eat() 时 ,会拿 Son1GrandsonMRO方法解析顺序表 中寻找,找到然后 super() 调用则是列表中下一个,这里是 Son2,然后 Son2.eat() 中使用了 super().eat(),此时是拿其本身 Son2Son2MRO方法解析顺序表 中寻找,然后 super().eat() 调用,则是列表的下一个 Parent.eat()

因此在 Grandsonsuper(Son1, self).eat() 调用的是 Son2.eat()

假如 super(Son2, self).eat() 调用的则是 Parent.eat()。结果如下

[<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>
]
grandson --- eat()parent --- 爱吃饭grandson --- 爱吃零食

因此只能使用 父类名 的形式调用 Son1.eat()只继承 Son1 的特性。如果不清楚 super()调用的谁,打印其

类名.mro(),对照 MRO方法解析顺序表,就一目了然。

总结

  • 方法解析顺序 Method Resolution Order,简称 MRO。主要用于在多继承时判断方法,属性的调用路径

  • 旧式类,没有共同的 object祖先且没有显式的指定其祖先。

  • 新式类,在 Python 2.x 版本中显式继承 object 或者其他新式类,Python3.x中则是隐式继承object

  • super().method() 相对于 类名.method(self),在 单继承 上用法基本无差

  • 多继承 上有区别,super() 方法 能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果

公众号

新建文件夹X

大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。

Python多继承及MRO顺序相关推荐

  1. python多继承顺序_Python多继承以及MRO顺序的使用

    多继承以及MRO顺序 1. 单独调用父类的方法 # coding=utf-8 print("******多继承使用类名.__init__ 发生的状态******") class P ...

  2. Python中菱形继承的MRO顺序及property属性

    Python中菱形继承的MRO顺序及property属性 文章目录 Python中菱形继承的MRO顺序及property属性 一.Python中菱形继承的MRO顺序 1. 单独调用父类的方法 2. 多 ...

  3. python 多继承与super使用详解_Python super()方法、多继承以及MRO顺序

    仅供学习,转载请注明出处 单独调用父类的方法 需求:编写一个类,然后再写一个子类进行继承,使用子类去调用父类的方法1. 使用方法1打印: 胖子老板,来包槟榔. 那么先写一个胖子老板的父类,执行一下: ...

  4. 多继承以及MRO顺序【super().的使用】

    多继承以及MRO顺序 1. 单独调用父类的方法 # coding=utf-8print("******多继承使用类名.__init__ 发生的状态******") class Pa ...

  5. python多继承顺序及分配,python多继承的查找顺序是什么?

    1.查找顺序 (1)本地优先,自己定义或重写的方法优先.本地没有的,按照继承列表,从左往右查找: (2)单调性,所有子类,也要满足查找顺序.也就是说 A 继承 B C,A 会先找 B 再找 C.但是在 ...

  6. python中的单继承,多继承和mro顺序

    python作为一门动态语言,是和c++一样支持面向对象编程的.相对对象编程有三大特性,分别是继承,封装和多态.今天我们重点讲解的是,python语言中的单继承和多继承. 继承概念: 如果一个类继承了 ...

  7. Python - 多继承与MRO

    (一)多继承 网上关于多继承.MRO和C3算法的讲解比较多,在此不再赘述. 我们可以利用类的__mro__ 属性或者 mro() 方法查看某个类的MRO列表(方法调用顺序).   (二)经典案例 当执 ...

  8. 多继承以及MRO顺序

    多继承指的是子类继承多个父类,可以通过三种方式访问父类的方法: 父类名.父类方法(self):这种方式容易造成父类方法被调用多次的问题(菱形继承问题),而且一旦父类名称发生变化,子类调用的地方都需要修 ...

  9. python多继承方式和顺序

    python 中继承方式有两种:深度优先.广度优先. 如图,B 继承 A, C 继承 A, D 继承 B 和 C. 深度优先遍历是从 D 开始往上搜索到 B,若 B 没有数据,则继续往上搜索到 A: ...

  10. python类继承的查找顺序问题

    python继承的顺序,也就是钻石继承问题,查找顺序是从子类到父类,从左到右,最后查找object,(简单地说,可以说是深度优先的查找方式) 以下面为例: class GrandFather(obje ...

最新文章

  1. Flex实现页面多态--state对象
  2. 使用批处理实现mysql数据库备份与上传
  3. Table嵌套去掉子table的外边框
  4. jqgrid的动态下拉框实现,并解决不能获取值的问题
  5. house price model
  6. SpringBoot Web原生组件注入(Servlet、Filter、Listener)
  7. reactjs 全局状态管理:redux的组成
  8. 基于ASP.NET Core 3.0的ABP v0.21已发布
  9. 《电路分析导论(原书第12版)》一1.2.2 真空电子时代
  10. 改变WCF service location的 hostName
  11. 仅用半小时,从Python爬取到BI可视化,告诉你深圳房价有多贵
  12. Java 8并发工具包简介
  13. Linux内存分配器SLOB,深入理解Linux内核之SLOB分配器
  14. python使用金山词霸的翻译功能
  15. Safari怎么开发扩展(插件)
  16. upc组队赛6 Bumped!【最短路】
  17. 新显卡出世,谈谈与深度学习有关的显卡架构和相关技术
  18. 牛客网 SQL17 10月的新户客单价和获客成本
  19. 使用Heartbeat实现双机热备
  20. media在HTML中作用,web前端:关于css中@media的一些基本使用

热门文章

  1. 服务产品(商品)评论中的产品特征挖掘方法
  2. web前端基础——Less语法
  3. 《实变函数简明教程》,P115,第14题(利用Lebesgue控制收敛定理求函数列Lebesgue积分的极限)
  4. 中外十大武侠片排行榜
  5. 用优盘装系统看不到计算机本身的硬盘,电脑u盘重装系统找不到硬盘的3大解决方法...
  6. [USACO2008 Mar]土地购买
  7. Latex 只在首页添加页眉页脚 修改局部字体大小
  8. VS2019的C++项目如何查看源文件(.h,.cc.cpp等)所在的工程
  9. 算法-动态规划-打家劫舍
  10. UMTS到LTE的系统架构演进(学习整理:LTE完全指南-LTE、LTE-Advanced、SAE、VolTE和4G移动通信)