需求:編寫一個類,而後再寫一個子類進行繼承,使用子類去調用父類的方法1。算法
使用方法1打印: 胖子老闆,來包檳榔。函數
那麼先寫一個胖子老闆的父類,執行一下:spa
class FatFather(object): def __init__(self, name): print('FatFather的init開始被調用') self.name = name print('FatFather的name是%s' % self.name) print('FatFather的init調用結束') def main(): ff = FatFather("胖子老闆的父親")
運行一下這個胖子老闆父類的構造方法__init__ 以下:code
if __name__ == "__main__": main()
FatFather的init開始被調用 FatFather的name是胖子老闆的父親 FatFather的init調用結束
好了,那麼下面來寫一個子類,也就是胖子老闆類,繼承上面的類排序
# 胖子老闆的父類 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)直接調用父類的方法。
運行結果以下:繼承
if __name__ == "__main__": main()
胖子老闆的類被調用啦! FatFather的init開始被調用 調用FatFather類的name是胖子老闆 FatFather的init調用結束 胖子老闆 的愛好是 打鬥地主
除了直接使用 FatFather.__init__(self,name) 的方法,還可使用super()方法來調用。it
那麼首先須要看super()方法的描述和語法理解一下super() 方法的使用。class
super() 函數是用於調用父類(超類)的一個方法。object
super 是用來解決多重繼承問題的,直接用類名調用父類方法在使用單繼承的時候沒問題,可是若是使用多繼承,會涉及到查找順序(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 :
class A: pass class B(A): def add(self, x): super().add(x)
class A(object): # Python2.x 記得繼承 object pass class B(A): def add(self, x): super(B, self).add(x)
# 胖子老闆的父類 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(): #ff = FatFather("胖子老闆的父親") fatboss = FatBoss("胖子老闆", "打鬥地主")
從上面使用super方法的時候,由於是單繼承,直接就可使用了。
運行以下:
if __name__ == "__main__": main()
胖子老闆的類被調用啦! FatFather的init開始被調用 調用FatFather類的name是胖子老闆 FatFather的init調用結束 胖子老闆 的愛好是 打鬥地主
那麼爲何說單繼承直接使用就能夠呢?由於super()方法若是多繼承的話,會涉及到一個MRO(繼承父類方法時的順序表) 的調用排序問題。
下面能夠打印一下看看單繼承的MRO順序(FatBoss.__mro__)。
# 胖子老闆的父類 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("胖子老闆", "打鬥地主")
上面的代碼使用 FatBoss.__mro__ 能夠打印出 FatBoss這個類通過 python解析器的 C3算法計算事後的繼承調用順序。
運行以下:
if __name__ == "__main__": main()
打印FatBoss類的MRO (<class '__main__.FatBoss'>, <class '__main__.FatFather'>, <class 'object'>) =========== 下面按照 MRO 順序執行super方法 ============= 胖子老闆的類被調用啦! FatFather的init開始被調用 調用FatFather類的name是胖子老闆 FatFather的init調用結束 胖子老闆 的愛好是 打鬥地主
從上面的結果 (<class '__main__.FatBoss'>, <class '__main__.FatFather'>, <class 'object'>) 能夠看出,super() 方法在 FatBoss 會直接調用父類是 FatFather ,因此單繼承是沒問題的。
那麼若是多繼承的話,會有什麼問題呢?
假設再寫一個胖子老闆的女兒類,和 胖子老闆的老婆類,此時女兒須要同時繼承 兩個類(胖子老闆類,胖子老闆老婆類)。
由於胖子老闆有一個愛好,胖子老闆的老婆須要幹活幹家務,那麼女兒須要幫忙同時兼顧。
此時女兒就是須要繼承使用這兩個父類的方法了,那麼該如何去寫呢?
下面來看看實現代碼:
# 胖子老闆的父類 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'>) =========== 下面按照 MRO 順序執行super方法 ============= 胖子老闆的女兒類被調用啦!要學會幹家務,還要會幫胖子老闆鬥地主 =============== 開始調用 FatBoss ======================== 胖子老闆的類被調用啦! =============== 開始調用 FatBossWife ======================== 胖子老闆的老婆類被調用啦!要學會幹家務 =============== 開始調用 FatFather ======================== FatFather的init開始被調用 調用FatFather類的name是胖子老闆 FatFather的init調用結束 =============== 結束調用 FatFather ======================== 胖子老闆 須要乾的家務是 拖地 =============== 結束調用 FatBossWife ======================== 胖子老闆 的愛好是 打鬥地主 =============== 結束調用 FatBoss ========================
從上面的運行結果來看,我特地給每一個類的調用開始以及結束都進行打印標識,能夠看到。
每一個類開始調用是根據MRO順序進行開始,而後逐個進行結束的。
還有就是因爲由於須要繼承不一樣的父類,參數不必定。
因此,全部的父類都應該加上不定參數*args , **kwargs ,否則參數不對應是會報錯的。
super().__init__相對於類名.__init__,在單繼承上用法基本無差
但在多繼承上有區別,super方法能保證每一個父類的方法只會執行一次,而使用類名的方法會致使方法被執行屢次,能夠嘗試寫個代碼來看輸出結果
多繼承時,使用super方法,對父類的傳參數,應該是因爲python中super的算法致使的緣由,必須把參數所有傳遞,不然會報錯
單繼承時,使用super方法,則不能所有傳遞,只能傳父類方法所需的參數,不然會報錯
多繼承時,相對於使用類名.__init__方法,要把每一個父類所有寫一遍, 而使用super方法,只需寫一句話便執行了所有父類的方法,這也是爲什麼多繼承須要所有傳參的一個緣由
如下的代碼的輸出將是什麼? 說出你的答案並解釋。
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x, Child1.x, Child2.x)
1 1 1
Child1.x = 2 print(Parent.x, Child1.x, Child2.x)
1 2 1
Parent.x = 3 print(Parent.x, Child1.x, Child2.x)
3 2 3