python面向對象進階-05super()方法詳解

單純調用父類方法

列子python

# 胖子老闆的父類
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)、重複調用(鑽石繼承)等種種問題。python3.x

配合搭配的mro小老弟

用法: print(最後子類名.mro()) 或者 print(最後子類名.__mro__)
MRO 就是類的方法解析順序表, 其實也就是繼承父類方法時的順序表。函數

super()語法

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

參數

type -- 類
object-or-type -- 類,通常是 self排序

Python3.x 和 Python2.x 的一個區別是:

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

例子以下:it

# 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(繼承父類方法時的順序表) 的調用排序問題。class

客官,菜(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 ,因此單繼承是沒問題的。object

多繼承使用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方法,只需寫一句話便執行了所有父類的方法,這也是爲什麼多繼承須要所有傳參的一個緣由

相關文章
相關標籤/搜索