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

多继承以及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。

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

(0)

相关推荐

  • python多继承(钻石继承)问题和解决方法简单示例

    本文实例讲述了python多继承(钻石继承)问题和解决方法.分享给大家供大家参考,具体如下: 在菱形多继承中,如果用父类.__init__()来调用父类的初始化方法,最上层会执行两次,所以遇到这种情况,python中用super.__init__()来解决这个问题. # -*- coding:utf-8 -*- #! python3 class Grand_father(object): def __init__(self): print('爷爷') class Father_left(Gran

  • Python面向对象程序设计多继承和多态用法示例

    本文实例讲述了Python面向对象程序设计多继承和多态用法.分享给大家供大家参考,具体如下: 多继承 就是一个子类继承多个父类: 多继承的例子,如下: # -*- coding:utf-8 -*- #! python3 class Base(object): def test(self): print("------base") class A(Base): def test1(self): print("-----test1") class B(Base): de

  • 在python里面运用多继承方法详解

    如何在PYTHON里面运用多继承 class Father: def hobby(self): print("love to play video game.") class Mother: def cook(self): print("love to cook anything.") #比如说有两个类,如果想要一个子类同时继承这两个类,应该怎么操作呢. class Father: def hobby(self): print("love to play

  • Python中的单继承与多继承实例分析

    本文实例讲述了Python中的单继承与多继承.分享给大家供大家参考,具体如下: 单继承 一.介绍 Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义.派生类的定义如下所示: class DerivedClassName(BaseClassName1): <statement-1> . . . <statement-N> 需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类

  • Python多继承原理与用法示例

    本文实例讲述了Python多继承原理与用法.分享给大家供大家参考,具体如下: python中使用多继承,会涉及到查找顺序(MRO).重复调用(钻石继承,也叫菱形继承问题)等 MRO MRO即method resolution order,用于判断子类调用的属性来自于哪个父类.在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类 从图中可以看出,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索 C3算法

  • Python面向对象程序设计之继承与多继承用法分析

    本文实例讲述了Python面向对象程序设计之继承与多继承.分享给大家供大家参考,具体如下: 1. 继承 在C++和Java中,使用继承时,子类的构造函数会自动调用父类的构造函数,但在Python中,子类必须显式的在__init__()函数中再次调用父类中的__init__()函数.如下例: class Employee(object): def __init__(self, name, salary = 0): self.name = name self.salary = salary def

  • Python多继承顺序实例分析

    本文实例讲述了Python多继承顺序.分享给大家供大家参考,具体如下: 示例1: #-*- coding:utf-8 -*- #!python2 class A(object): def caller(self): print 'A caller' self.called() def called(self): print 'A called' class B(object): def called(self): print 'B called' class C(B,A): pass if __

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

    多继承以及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,

  • 一篇文章搞懂Python Unittest测试方法的执行顺序

    目录 Unittest 回到主题 源码初窥 回到问题的本质 1. 以字典序的方式编写test方法 2. 回归本质,从根本解决问题 总结 Unittest unittest大家应该都不陌生.它作为一款博主在5-6年前最常用的单元测试框架,现在正被pytest,nose慢慢蚕食. 渐渐地,看到大家更多的讨论的内容从unittest+HTMLTestRunner变为pytest+allure2等后起之秀. 不禁感慨,终究是自己落伍了,跟不上时代的大潮了. 回到主题 感慨完了,回到正文.虽然unitte

  • python类继承用法实例分析

    本文实例讲述了python类继承用法.分享给大家供大家参考.具体方法如下: #!/usr/bin/python # Filename: inherit.py class SchoolMember: '''Represents any school member.''' def __init__(self, name, age): self.name = name self.age = age print'(Initialized SchoolMember: %s)'% self.name def

  • 详解Python函数作用域的LEGB顺序

    本文为大家介绍了Python函数作用域的查找顺序,供大家参考,具体内容如下 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.LEGB是作什么用的? 为什么非要介绍这个呢?或者说它们的作用是什么? 原因是因为我们的在学习Python函数的时候,经常会遇到很多定义域的问题,全部变量,内部变量,内部嵌入的函数,等等,Python是如何查找的呢?以及Python又是按照什么顺序来查找

  • python类继承与子类实例初始化用法分析

    本文实例讲述了python类继承与子类实例初始化用法.分享给大家供大家参考.具体分析如下: [ 先贴参考书籍原文(中文英文对照)] __init__方法介绍: If a base class has an __init__() method the derived class's __init__() method must explicitly call it to ensure proper initialization of the base class part of the insta

  • 详解java中继承关系类加载顺序问题

    详解java中继承关系类加载顺序问题 实例代码: /** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ public SonClass(){ System.out.println("SonClass's constructor"); } { System.out.println("SonClass's block");} static { System.out

  • python DataFrame 修改列的顺序实例

    假设我有一个DataFrame(df)如下: name age id mike 10 1 tony 14 2 lee 20 3 现在我想把id 放到最前面,变成: id name age df_id = df.id df = df.drop('id',axis=1) df.insert(0,'id',df_id) 以上这篇python DataFrame 修改列的顺序实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们. 您可能感兴趣的文章: Python中datet

  • 对Python random模块打乱数组顺序的实例讲解

    在我们使用一些数据的过程中,我们想要打乱数组内数据的顺序但不改变数据本身,可以通过改变索引值来实现,也就是将索引值重新随机排列,然后生成新的数组.功能主要由python中random模块的sample()函数实现. sample(population, k) method of random.Random instance Chooses k unique random elements from a population sequence or set. 下面的代码实现的是打乱iris数据,i

随机推荐