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将图片批量从png格式转换至WebP格式
Aug 22 Python
Python之py2exe打包工具详解
Jun 14 Python
python requests 使用快速入门
Aug 31 Python
python实现决策树分类(2)
Aug 30 Python
python爬取网易云音乐评论
Nov 16 Python
浅谈Python的条件判断语句if/else语句
Mar 21 Python
Python 中Django安装和使用教程详解
Jul 03 Python
python3 enum模块的应用实例详解
Aug 12 Python
Python生成随机验证码代码实例解析
Jun 09 Python
Python使用Chrome插件实现爬虫过程图解
Jun 09 Python
Python正则表达式高级使用方法汇总
Jun 18 Python
基于PyTorch实现一个简单的CNN图像分类器
May 29 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 setcookie设置Cookie用法(及设置无效的问题)
2011/07/13 PHP
php常用Stream函数集介绍
2013/06/24 PHP
PHP实现数字补零功能的2个函数介绍
2014/05/12 PHP
PHP向socket服务器收发数据的方法
2015/01/24 PHP
ThinkPHP框架整合微信支付之JSAPI模式图文详解
2019/04/09 PHP
JavaScript入门教程(11) js事件处理
2009/01/31 Javascript
菜鸟javascript基础资料整理3 正则
2010/12/06 Javascript
js实现ctrl+v粘贴上传图片(兼容chrome、firefox、ie11)
2016/03/09 Javascript
JS去除重复并统计数量的实现方法
2016/12/15 Javascript
解析JavaScript模仿块级作用域
2016/12/29 Javascript
jQuery实现div跟随鼠标移动
2020/08/20 jQuery
详解Angular路由 ng-route和ui-router的区别
2017/05/22 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
2017/09/20 Javascript
微信小程序实现鼠标拖动效果示例
2017/12/01 Javascript
基于vue v-for 循环复选框-默认勾选第一个的实现方法
2018/03/03 Javascript
layui获取选中行数据的实例讲解
2018/08/19 Javascript
微信小程序仿知乎实现评论留言功能
2018/11/28 Javascript
vue的.vue文件是怎么run起来的(vue-loader)
2018/12/10 Javascript
Vue 中如何正确引入第三方模块的方法步骤
2019/05/05 Javascript
JS中类的静态方法,静态变量,实例方法,实例变量区别与用法实例分析
2020/03/14 Javascript
js实现鼠标拖曳效果
2020/12/30 Javascript
Python使用PIL模块生成随机验证码
2017/11/21 Python
Python2.7环境Flask框架安装简明教程【已测试】
2018/07/13 Python
python traceback捕获并打印异常的方法
2018/08/31 Python
对python中xlsx,csv以及json文件的相互转化方法详解
2018/12/25 Python
英国顶级家庭折扣店:The Works
2017/09/06 全球购物
美国廉价机票预订网站:Cheapfaremart
2018/04/28 全球购物
SHEIN香港:价格实惠的女性时尚服装
2018/08/14 全球购物
教师申诉制度
2014/01/29 职场文书
广告宣传策划方案
2014/05/21 职场文书
婚礼新人答谢词
2015/01/04 职场文书
求职自荐信范文(优秀篇)
2015/03/27 职场文书
小学生心理健康活动总结
2015/05/08 职场文书
Java数据结构之链表相关知识总结
2021/06/18 Java/Android
Jmerte 分布式压测及分布式压测配置
2022/04/30 Java/Android
python中使用redis用法详解
2022/12/24 Redis