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正则表达式操作指南(re使用)
Sep 06 Python
python list 合并连接字符串的方法
Mar 09 Python
python函数返回多个值的示例方法
Dec 04 Python
Python实现网站注册验证码生成类
Jun 08 Python
Python对象中__del__方法起作用的条件详解
Nov 01 Python
python使用for循环计算0-100的整数的和方法
Feb 01 Python
django的分页器Paginator 从django中导入类
Jul 25 Python
Python函数装饰器原理与用法详解
Aug 16 Python
PyTorch中常用的激活函数的方法示例
Aug 20 Python
解决pip install psycopg2出错问题
Jul 09 Python
scrapy处理python爬虫调度详解
Nov 23 Python
Selenium Webdriver元素定位的八种常用方式(小结)
Jan 13 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
Laravel 5框架学习之表单
2015/04/08 PHP
Yii操作数据库实现动态获取表名的方法
2016/03/29 PHP
浅析PHP中的i++与++i的区别及效率
2016/06/15 PHP
php和js实现根据子网掩码和ip计算子网功能示例
2019/11/09 PHP
JavaScript使用prototype定义对象类型(转)[
2006/12/22 Javascript
jQuery 学习入门篇附实例代码
2010/03/16 Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
js特效,页面下雪的小例子
2013/06/17 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
使用pjax实现无刷新更改页面url
2015/02/05 Javascript
BootStrap的table表头固定tbody滚动的实例代码
2016/08/24 Javascript
js初始化验证实例详解
2016/11/26 Javascript
微信小程序 地图map详解及简单实例
2017/01/10 Javascript
使用javascript做在线算法编程
2018/05/25 Javascript
微信小程序拍照和摄像功能实现方法示例
2019/02/01 Javascript
Vue中的组件及路由使用实例代码详解
2019/05/22 Javascript
使用Python的Scrapy框架十分钟爬取美女图
2016/12/26 Python
python 字符串转列表 list 出现\ufeff的解决方法
2017/06/22 Python
Java编程迭代地删除文件夹及其下的所有文件实例
2018/02/10 Python
便捷提取python导入包的属性方法
2018/10/15 Python
Pytorch GPU显存充足却显示out of memory的解决方式
2020/01/13 Python
新年福利来一波之Python轻松集齐五福(demo)
2020/01/20 Python
使用Python和百度语音识别生成视频字幕的实现
2020/04/09 Python
MAC平台基于Python Appium环境搭建过程图解
2020/08/13 Python
英国门销售网站:Green Tree Doors
2020/01/07 全球购物
Myprotein荷兰官网:欧洲第一运动营养品牌
2020/07/11 全球购物
结婚喜宴主持词
2014/03/14 职场文书
《火烧云》教学反思
2014/04/12 职场文书
高中生评语大全
2014/04/25 职场文书
党的群众路线教育实践活动对照检查材料(四风)
2014/09/27 职场文书
茶楼服务员岗位职责
2015/02/09 职场文书
2015年导购员工作总结
2015/04/25 职场文书
四十年同学聚会致辞
2015/07/28 职场文书
python中subplot大小的设置步骤
2021/06/28 Python
漫改真人电影「萌系男友是燃燃的橘色」公开先导视觉图
2022/03/21 日漫
zabbix配置nginx监控的实现
2022/05/25 Servers