python面向对象进阶-05super()方法详解

单纯调用父类方法

列子

# 胖子老板的父类
class FatFather(object):
    def __init__(self, name):
        print('FatFather的init开始被调用')
        self.name = name
        print('调用FatFather类的name是%s' % self.name)
        print('FatFather的init调用结束')

# 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
    def __init__(self, name, hobby):
        print('胖子老板的类被调用啦!')
        self.hobby = hobby
        FatFather.__init__(self, name)  # 直接调用父类的构造方法
        print("%s 的爱好是 %s" % (name, self.hobby))

def main():
    #ff = FatFather("胖子老板的父亲")
    fatboss = FatBoss("胖子老板", "打斗地主")

使用FatFather.init(self,name)直接调用父类的方法。

super()方法登场

super()描述

super() 函数是用于调用父类(超类)的一个方法。
super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

配合搭配的mro小老弟

用法: print(最后子类名.mro()) 或者 print(最后子类名.mro)
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

super()语法

super(type[, object-or-type])

参数

type -- 类
object-or-type -- 类,一般是 self

Python3.x 和 Python2.x 的一个区别是:

Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :

例子如下:

# Python3.x 实例:
class A:
    pass
class B(A):
    def add(self, x):
        super().add(x)
#Python2.x 实例:
class A(object):   # Python2.x 记得继承 object
    pass
class B(A):
    def add(self, x):
        super(B, self).add(x)

单继承使用supper()

那么为什么说单继承直接使用就可以呢?因为super()方法如果多继承的话,会涉及到一个MRO(继承父类方法时的顺序表) 的调用排序问题。

客官,菜(code)来啦!!!!

# 胖子老板的父类
# 胖子老板的父类
class FatFather(object):
    def __init__(self, name):
        print('FatFather的init开始被调用')
        self.name = name
        print('调用FatFather类的name是%s' % self.name)
        print('FatFather的init调用结束')

# 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
    def __init__(self, name, hobby):
        print('胖子老板的类被调用啦!')
        self.hobby = hobby
        #FatFather.__init__(self,name)   # 直接调用父类的构造方法
        super().__init__(name)
        print("%s 的爱好是 %s" % (name, self.hobby))

def main():
    print("打印FatBoss类的MRO")
    print(FatBoss.__mro__)
    print()
    print("=========== 下面按照 MRO 顺序执行super方法 =============")
    fatboss = FatBoss("胖子老板", "打斗地主")

if __name__ == "__main__":
    main()

上面的代码使用 FatBoss.mro 可以打印出 FatBoss这个类经过 python解析器的 C3算法计算过后的继承调用顺序。
(<class 'main.FatBoss'>, <class 'main.FatFather'>, <class 'object'>)
从上面的结果 (<class 'main.FatBoss'>, <class 'main.FatFather'>, <class 'object'>) 可以看出,super() 方法在 FatBoss 会直接调用父类是 FatFather ,所以单继承是没问题的。

多继承使用super()

每个类开始调用是根据MRO顺序进行开始,然后逐个进行结束的。
还有就是由于因为需要继承不同的父类,参数不一定。
所以,所有的父类都应该加上不定参数*args , **kwargs ,不然参数不对应是会报错的。

客官,菜(code)来啦!!!!

# 胖子老板的父类
class FatFather(object):
    def __init__(self, name, *args, **kwargs):
        print()
        print("=============== 开始调用 FatFather  ========================")
        print('FatFather的init开始被调用')
        self.name = name
        print('调用FatFather类的name是%s' % self.name)
        print('FatFather的init调用结束')
        print()
        print("=============== 结束调用 FatFather  ========================")

# 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
    def __init__(self, name, hobby, *args, **kwargs):
        print()
        print("=============== 开始调用 FatBoss  ========================")
        print('胖子老板的类被调用啦!')
        #super().__init__(name)
        ## 因为多继承传递的参数不一致,所以使用不定参数
        super().__init__(name, *args, **kwargs)
        print("%s 的爱好是 %s" % (name, hobby))
        print()
        print("=============== 结束调用 FatBoss  ========================")

# 胖子老板的老婆类 继承 FatFather类
class FatBossWife(FatFather):
    def __init__(self, name, housework, *args, **kwargs):
        print()
        print("=============== 开始调用 FatBossWife  ========================")
        print('胖子老板的老婆类被调用啦!要学会干家务')
        #super().__init__(name)
        ## 因为多继承传递的参数不一致,所以使用不定参数
        super().__init__(name, *args, **kwargs)
        print("%s 需要干的家务是 %s" % (name, housework))
        print()
        print("=============== 结束调用 FatBossWife  ========================")

# 胖子老板的女儿类 继承 FatBoss FatBossWife类
class FatBossGril(FatBoss, FatBossWife):
    def __init__(self, name, hobby, housework):
        print('胖子老板的女儿类被调用啦!要学会干家务,还要会帮胖子老板斗地主')
        super().__init__(name, hobby, housework)

def main():
    print("打印FatBossGril类的MRO")
    print(FatBossGril.__mro__)
    print()
    print("=========== 下面按照 MRO 顺序执行super方法 =============")
    gril = FatBossGril("胖子老板", "打斗地主", "拖地")

if __name__ == "__main__":
    main()

打印FatBossGril类的MRO:
(<class 'main.FatBossGril'>, <class 'main.FatBoss'>, <class 'main.FatBossWife'>, <class 'main.FatFather'>, <class 'object'>)

关于super()使用的注意事项:
1.super().__init__相对于类名.init,在单继承上用法基本无差
2.但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,可以尝试写个代码来看输出结果
3.多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
4.单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
5.多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因

posted @ 2019-09-21 10:54  suren_apan  阅读(124)  评论(0编辑  收藏  举报