多继承以及MRO顺序

1. 单独调用父类的方法

# coding=utf-8print("******多继承使用类名.__init__ 发生的状态******")
class Parent(object):def __init__(self, name):print('parent的init开始被调用')self.name = nameprint('parent的init结束被调用')class Son1(Parent):def __init__(self, name, age):print('Son1的init开始被调用')self.age = ageParent.__init__(self, name)print('Son1的init结束被调用')class Son2(Parent):def __init__(self, name, gender):print('Son2的init开始被调用')self.gender = genderParent.__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 = nameprint('parent的init结束被调用')class Son1(Parent):def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数print('Son1的init开始被调用')self.age = agesuper().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数print('Son1的init结束被调用')class Son2(Parent):def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数print('Son2的init开始被调用')self.gender = gendersuper().__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 = nameprint('parent的init结束被调用')class Son1(Parent):def __init__(self, name, age):print('Son1的init开始被调用')self.age = agesuper().__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__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因

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

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

class Parent(object):x = 1class Child1(Parent):passclass Child2(Parent):passprint(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)

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

1 1 1
1 2 1
3 2 3

使你困惑或是惊奇的是关于最后一行的输出是 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。

多继承以及MRO顺序【super().的使用】相关推荐

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

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

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

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

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

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

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

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

  5. 多继承以及MRO顺序

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

  6. python 多继承与super使用详解_继承中的MRO与super详解

    Python进阶-继承中的MRO与super 写在前面如非特别说明,下文均基于Python3 摘要 本文讲述Python继承关系中如何通过super()调用"父类"方法,super ...

  7. pythonsupermro_Python高级编程之继承问题详解(super与mro)

    本文实例讲述了Python高级编程之继承问题.分享给大家供大家参考,具体如下: 多继承问题 1.单独调用父类: 一个子类同时继承自多个父类,又称菱形继承.钻石继承. 使用父类名.init(self)方 ...

  8. Python - 多继承与MRO

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

  9. python 钻石继承_python3--object类,继承与派生,super方法,钻石继承问题

    python3--object类,继承与派生,super方法,钻石继承问题 发布时间:2018-04-13 20:38:05编辑:Run阅读(1914) 昨天内容复习 组合:什么有什么的关系(例:老师 ...

最新文章

  1. RedHat企业版的安装(一)
  2. 北邮计算机学不学单片机,北邮小学期PC单片机.docx
  3. 14年数字化转型经验,总结出数据团队的5个级别,最后1个没人做到
  4. 矩阵乘法c语言蓝桥杯,[蓝桥杯][基础练习VIP]矩阵乘法 (C语言代码)
  5. scala递归求斐波那契数列
  6. Go-闭包和匿名函数讲解
  7. pool.map()爬取美文网标题内容
  8. Flex builder 3 激活码
  9. MATLAB疲劳检测系统
  10. Vue router 默认加载 views 文件夹下全部vue文件
  11. 申城一叙:SDCC 2017·上海站数据库专场讲师+议题抢鲜版纵览
  12. centos/redhat kernel-debug-info-xx.rpm与kernel-debuginfo-xx.rpm区别
  13. 在国内愚人节可以开的10个玩笑
  14. vue3.2+element-plus+ts节假日管理界面
  15. 推荐一本迷你中文书《JavaScript Promise迷你书(中文版)》
  16. 手机刷机是什么意思?快速了解手机刷机基本概念
  17. 《自然语言处理:基于预训练模型的方法》读书笔记:第2章 自然语言处理基础
  18. docker安装bind
  19. Kelvin Test
  20. Oracle数据库对小数点的操作

热门文章

  1. 15条常用的视频音频编辑脚本命令(mencoder/ffmpeg等)
  2. 解决 dockerfile 构建镜像报错: [WARNING]: Empty continuation lines will become errors in a future release.
  3. xcode windows版安装使用教程
  4. sql:无法解决 equal to 操作中 Chinese_PRC_CI_AS 和 Chinese_Taiwan_Stroke_CI_AS 之间的排序规则冲突。...
  5. 初识python之函数基础
  6. 【hdu 6444】Neko's loop
  7. 计算机程序设计艺术+第3卷:排序与查找(第二版)pdf
  8. Python全局变量和局部变量
  9. python3字符串属性(二)
  10. PHP内核探索之变量(6)- 后续内核探索系列大纲备忘