子类中执行父类的方法(引出super()与mro列表)

1. 我们先想一下在python中如果子类方法中想执行父类的方法,有什么方式?大概有三种:

  • Parent.__init__(self, name)     # 通过父类的名字,指定调用父类的方法
  • super().__init__(name, *args, **kwargs)  # 通过super()自动调用父类的方法
  • super(Son2, self).__init__(name, *args, **kwargs)  # 通过super()并且传入一个类型名字,执行某个类的方法,这样就跳开super默认的执行顺序

2. 下面举例说明每一种方式

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, '')
单独调用父类的方法

在例子中,son1 son2 继承了parent类,Grandson 继承了son1 son2,并且在son1 son2 的构造方法中分别调用了父类的构造方法,在Grandson的构造方法中调用了 son1 son2 的构造方法。

运行结果:

父类parent的构造方法被执行2次。这就是直接使用父类名去调用的稍微不好的地方。

randson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男

鉴于上面调用的不足之处,有了super()方式的调用。

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调用

首先,如果一个类继承多各类,比如本例中的 Grandson, 那么该类有一个__mro__的属性,该属性的值表示类的继承顺序。

(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)

那么如果使用super调用父类方法时,就依此顺序执行它的父类的方法。

如图描述

这样执行下来,parent类中的构造方法,就被执行一次。

执行顺序用途表示如下图

 

而在super()函数中传入类型参数时,执行这个指定类的父类的方法.

 

posted @ 2019-01-18 10:36  20180616  阅读(254)  评论(0编辑  收藏  举报