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脚本将文字转换为图片的实例分享
Aug 29 Python
python将ansible配置转为json格式实例代码
May 15 Python
python数字图像处理之高级滤波代码详解
Nov 23 Python
python 编码规范整理
May 05 Python
Python3连接SQLServer、Oracle、MySql的方法
Jun 28 Python
Python 创建新文件时避免覆盖已有的同名文件的解决方法
Nov 16 Python
Django中提供的6种缓存方式详解
Aug 05 Python
python进阶之自定义可迭代的类
Aug 20 Python
Python 根据数据模板创建shapefile的实现
Nov 26 Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
Mar 20 Python
Python unittest单元测试框架及断言方法
Apr 15 Python
python多线程和多进程关系详解
Dec 14 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警告Cannot use a scalar value as an array的解决方法
2012/01/11 PHP
php中的注释、变量、数组、常量、函数应用介绍
2012/11/16 PHP
解析PHP实现下载文件的两种方法
2013/07/05 PHP
PHP怎么实现网站保存快捷方式方便用户随时浏览
2013/08/15 PHP
php获取指定数量随机字符串的方法
2017/02/06 PHP
php微信分享到朋友圈、QQ、朋友、微博
2019/02/18 PHP
onpropertypchange
2006/07/01 Javascript
javascript 一段左右两边随屏滚动的代码
2009/06/18 Javascript
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
JS获取当前网址、主机地址项目根路径
2013/11/19 Javascript
Three.js快速入门教程
2016/09/09 Javascript
JS在浏览器中解析Base64编码图像
2017/02/09 Javascript
vue.js 使用axios实现下载功能的示例
2018/03/05 Javascript
JS实现点击按钮可实现编辑功能
2018/07/03 Javascript
LayUi中接口传数据成功,表格不显示数据的解决方法
2018/08/19 Javascript
Angular resolve基础用法详解
2018/10/03 Javascript
微信小程序 WXML节点信息查询详解
2019/07/29 Javascript
layUI使用layer.open,在content打开数据表格,获取值并返回的方法
2019/09/26 Javascript
原生JavaScript之es6中Class的用法分析
2020/02/23 Javascript
python实现的一个p2p文件传输实例
2014/06/04 Python
pandas中的DataFrame按指定顺序输出所有列的方法
2018/04/10 Python
python3下使用cv2.imwrite存储带有中文路径图片的方法
2018/05/10 Python
详解Django-auth-ldap 配置方法
2018/12/10 Python
python 并发下载器实现方法示例
2019/11/22 Python
Python原始套接字编程实例解析
2020/01/29 Python
pygame实现飞机大战
2020/03/11 Python
Python 自由定制表格的实现示例
2020/03/20 Python
Luxplus荷兰:以会员价购买美容产品等,独家优惠
2019/08/30 全球购物
试解释COMMIT操作和ROLLBACK操作的语义
2014/07/25 面试题
工程地质勘察专业大学生求职信
2013/10/13 职场文书
实习教师自我鉴定
2013/12/09 职场文书
公司面试感谢信
2014/02/01 职场文书
《胖乎乎的小手》教学反思
2014/02/26 职场文书
警示教育片观后感
2015/06/17 职场文书
最新农村养殖致富:资金投入较低的创业项目有哪些?
2019/09/26 职场文书
Redis特殊数据类型HyperLogLog基数统计算法讲解
2022/06/01 Redis