Python多继承以及MRO顺序的使用


Posted in Python onNovember 11, 2019

多继承以及MRO顺序

1. 单独调用父类的方法

# coding=utf-8

print("******多继承使用类名.__init__ 发生的状态******")
class Parent(object):
 def __init__(self, name):
  print('parent的init开始被调用')
  self.name = name
  print('parent的init结束被调用')

class Son1(Parent):
 def __init__(self, name, age):
  print('Son1的init开始被调用')
  self.age = age
  Parent.__init__(self, name)
  print('Son1的init结束被调用')

class Son2(Parent):
 def __init__(self, name, gender):
  print('Son2的init开始被调用')
  self.gender = gender
  Parent.__init__(self, name)
  print('Son2的init结束被调用')

class Grandson(Son1, Son2):
 def __init__(self, name, age, gender):
  print('Grandson的init开始被调用')
  Son1.__init__(self, name, age) # 单独调用父类的初始化方法
  Son2.__init__(self, name, gender)
  print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)

print("******多继承使用类名.__init__ 发生的状态******\n\n")

运行结果:

******多继承使用类名.__init__ 发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__ 发生的状态******

2. 多继承中super调用有所父类的被重写的方法

print("******多继承使用super().__init__ 发生的状态******")
class Parent(object):
 def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
  print('parent的init开始被调用')
  self.name = name
  print('parent的init结束被调用')

class Son1(Parent):
 def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
  print('Son1的init开始被调用')
  self.age = age
  super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
  print('Son1的init结束被调用')

class Son2(Parent):
 def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数
  print('Son2的init开始被调用')
  self.gender = gender
  super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数
  print('Son2的init结束被调用')

class Grandson(Son1, Son2):
 def __init__(self, name, age, gender):
  print('Grandson的init开始被调用')
  # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
  # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
  # super(Grandson, self).__init__(name, age, gender)
  super().__init__(name, age, gender)
  print('Grandson的init结束被调用')

print(Grandson.__mro__)

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用super().__init__ 发生的状态******\n\n")

运行结果:

******多继承使用super().__init__ 发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__ 发生的状态******

注意:

1.  以上2个代码执行的结果不同
2.  如果2个子类中都继承了父类,当在子类中通过父类名调用时,parent被执行了2次
3.  如果2个子类中都继承了父类,当在子类中通过super调用时,parent被执行了1次

3. 单继承中super

print("******单继承使用super().__init__ 发生的状态******")
class Parent(object):
 def __init__(self, name):
  print('parent的init开始被调用')
  self.name = name
  print('parent的init结束被调用')

class Son1(Parent):
 def __init__(self, name, age):
  print('Son1的init开始被调用')
  self.age = age
  super().__init__(name) # 单继承不能提供全部参数
  print('Son1的init结束被调用')

class Grandson(Son1):
 def __init__(self, name, age, gender):
  print('Grandson的init开始被调用')
  super().__init__(name, age) # 单继承不能提供全部参数
  print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
#print('性别:', gs.gender)
print("******单继承使用super().__init__ 发生的状态******\n\n")

总结

  1. super().__init__相对于类名.init,在单继承上用法基本无差
  2. 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果
  3. 多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
  4. 单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
  5. 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍,
  6. 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因

小试牛刀(以下为面试题)

以下的代码的输出将是什么? 说出你的答案并解释。

class Parent(object):
 x = 1

class Child1(Parent):
 pass

class Child2(Parent):
 pass

print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)

答案, 以上代码的输出是:

使你困惑或是惊奇的是关于最后一行的输出是 3 2 3 而不是 3 2 1。为什么改变了 Parent.x 的值还会改变 Child2.x
的值,但是同时 Child1.x 值却没有改变?

这个答案的关键是,在 Python中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到(如果这个被引用的变量名既没有在自己所在的类又没有在祖先类中找到,会引发一个 AttributeError 异常 )。

因此,在父类中设置 x = 1 会使得类变量 x 在引用该类和其任何子类中的值为 1。这就是因为第一个 print 语句的输出是 1 1 1。
随后,如果任何它的子类重写了该值(例如,我们执行语句 Child1.x = 2),然后,该值仅仅在子类中被改变。这就是为什么第二个print 语句的输出是 1 2 1。

最后,如果该值在父类中被改变(例如,我们执行语句 Parent.x =
3),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是 Child2)。这就是为什么第三个 print 输出是 3 2 3。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python的字典和列表的使用中一些需要注意的地方
Apr 24 Python
Python中文件I/O高效操作处理的技巧分享
Feb 04 Python
python GUI实例学习
Nov 21 Python
python Crypto模块的安装与使用方法
Dec 21 Python
python实现合并多个list及合并多个django QuerySet的方法示例
Jun 11 Python
django基于cors解决跨域请求问题详解
Aug 06 Python
python中web框架的自定义创建
Sep 08 Python
解决pycharm上的jupyter notebook端口被占用问题
Dec 17 Python
python lambda函数及三个常用的高阶函数
Feb 05 Python
Django models文件模型变更错误解决
May 11 Python
使用pytorch 筛选出一定范围的值
Jun 28 Python
Lombok插件安装(IDEA)及配置jar包使用详解
Nov 04 Python
python 有效的括号的实现代码示例
Nov 11 #Python
Python+OpenCV实现实时眼动追踪的示例代码
Nov 11 #Python
python的pyecharts绘制各种图表详细(附代码)
Nov 11 #Python
python OpenCV GrabCut使用实例解析
Nov 11 #Python
Python上下文管理器用法及实例解析
Nov 11 #Python
Django 请求Request的具体使用方法
Nov 11 #Python
浅谈Python类中的self到底是干啥的
Nov 11 #Python
You might like
PHP实现网上点歌(二)
2006/10/09 PHP
PHP 身份验证方面的函数
2009/10/11 PHP
数据库中排序的对比及使用条件详解
2012/02/23 PHP
php中随机函数mt_rand()与rand()性能对比分析
2014/12/01 PHP
laravel 操作数据库常用函数的返回值方法
2019/10/11 PHP
jquery 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
2010/04/18 Javascript
nodejs 后缀名判断限制代码
2011/03/31 NodeJs
巧用jquery解决下拉菜单被Div遮挡的相关问题
2014/02/13 Javascript
js完美实现@提到好友特效(兼容各大浏览器)
2015/03/16 Javascript
JS实现页面跳转参数不丢失的方法
2016/11/28 Javascript
js实现导航栏中英文切换效果
2017/01/16 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
JQuery 选择器、DOM节点操作练习实例
2017/09/28 jQuery
基于jQuery ztree实现表格风格的树状结构
2018/08/31 jQuery
vue实现新闻展示页的步骤详解
2019/04/11 Javascript
Vue+Node实现商品列表的分页、排序、筛选,添加购物车功能详解
2019/12/07 Javascript
angula中使用iframe点击后不执行变更检测的问题
2020/05/10 Javascript
vue.js实现简单购物车功能
2020/05/30 Javascript
[41:12]Liquid vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.24
2019/09/10 DOTA
python避免死锁方法实例分析
2015/06/04 Python
Python中模块string.py详解
2017/03/12 Python
淘宝秒杀python脚本 扫码登录版
2019/09/19 Python
在Pytorch中计算卷积方法的区别详解(conv2d的区别)
2020/01/03 Python
Python 使用 environs 库定义环境变量的方法
2020/02/25 Python
Python依赖包迁移到断网环境操作
2020/07/13 Python
HTML5实践-图片设置成灰度图
2012/11/12 HTML / CSS
英国在线珠宝店:The Jewel Hut
2017/03/20 全球购物
自荐信包含哪些内容
2013/10/30 职场文书
高级电工工作职责
2013/11/21 职场文书
客服专员岗位职责范本
2013/11/29 职场文书
工地门卫岗位职责
2013/12/30 职场文书
社区党员先进事迹
2014/01/22 职场文书
四个太阳教学反思
2014/02/01 职场文书
十八届三中全会个人学习材料
2014/02/13 职场文书
亲子活动总结
2014/04/26 职场文书
新文化运动的基本口号
2014/06/21 职场文书