Python多繼承以及MRO順序的使用
多繼承以及MRO順序
1. 單獨(dú)調(diào)用父類的方法
# coding=utf-8 print("******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******") class Parent(object): def __init__(self, name): print('parent的init開始被調(diào)用') self.name = name print('parent的init結(jié)束被調(diào)用') class Son1(Parent): def __init__(self, name, age): print('Son1的init開始被調(diào)用') self.age = age Parent.__init__(self, name) print('Son1的init結(jié)束被調(diào)用') class Son2(Parent): def __init__(self, name, gender): print('Son2的init開始被調(diào)用') self.gender = gender Parent.__init__(self, name) print('Son2的init結(jié)束被調(diào)用') class Grandson(Son1, Son2): def __init__(self, name, age, gender): print('Grandson的init開始被調(diào)用') Son1.__init__(self, name, age) # 單獨(dú)調(diào)用父類的初始化方法 Son2.__init__(self, name, gender) print('Grandson的init結(jié)束被調(diào)用') gs = Grandson('grandson', 12, '男') print('姓名:', gs.name) print('年齡:', gs.age) print('性別:', gs.gender) print("******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******\n\n")
運(yùn)行結(jié)果:
******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******
Grandson的init開始被調(diào)用
Son1的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son1的init結(jié)束被調(diào)用
Son2的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son2的init結(jié)束被調(diào)用
Grandson的init結(jié)束被調(diào)用
姓名: grandson
年齡: 12
性別: 男
******多繼承使用類名.__init__ 發(fā)生的狀態(tài)******
2. 多繼承中super調(diào)用有所父類的被重寫的方法
print("******多繼承使用super().__init__ 發(fā)生的狀態(tài)******") class Parent(object): def __init__(self, name, *args, **kwargs): # 為避免多繼承報(bào)錯(cuò),使用不定長參數(shù),接受參數(shù) print('parent的init開始被調(diào)用') self.name = name print('parent的init結(jié)束被調(diào)用') class Son1(Parent): def __init__(self, name, age, *args, **kwargs): # 為避免多繼承報(bào)錯(cuò),使用不定長參數(shù),接受參數(shù) print('Son1的init開始被調(diào)用') self.age = age super().__init__(name, *args, **kwargs) # 為避免多繼承報(bào)錯(cuò),使用不定長參數(shù),接受參數(shù) print('Son1的init結(jié)束被調(diào)用') class Son2(Parent): def __init__(self, name, gender, *args, **kwargs): # 為避免多繼承報(bào)錯(cuò),使用不定長參數(shù),接受參數(shù) print('Son2的init開始被調(diào)用') self.gender = gender super().__init__(name, *args, **kwargs) # 為避免多繼承報(bào)錯(cuò),使用不定長參數(shù),接受參數(shù) print('Son2的init結(jié)束被調(diào)用') class Grandson(Son1, Son2): def __init__(self, name, age, gender): print('Grandson的init開始被調(diào)用') # 多繼承時(shí),相對于使用類名.__init__方法,要把每個(gè)父類全部寫一遍 # 而super只用一句話,執(zhí)行了全部父類的方法,這也是為何多繼承需要全部傳參的一個(gè)原因 # super(Grandson, self).__init__(name, age, gender) super().__init__(name, age, gender) print('Grandson的init結(jié)束被調(diào)用') print(Grandson.__mro__) gs = Grandson('grandson', 12, '男') print('姓名:', gs.name) print('年齡:', gs.age) print('性別:', gs.gender) print("******多繼承使用super().__init__ 發(fā)生的狀態(tài)******\n\n")
運(yùn)行結(jié)果:
******多繼承使用super().__init__ 發(fā)生的狀態(tài)******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init開始被調(diào)用
Son1的init開始被調(diào)用
Son2的init開始被調(diào)用
parent的init開始被調(diào)用
parent的init結(jié)束被調(diào)用
Son2的init結(jié)束被調(diào)用
Son1的init結(jié)束被調(diào)用
Grandson的init結(jié)束被調(diào)用
姓名: grandson
年齡: 12
性別: 男
******多繼承使用super().__init__ 發(fā)生的狀態(tài)******
注意:
1. 以上2個(gè)代碼執(zhí)行的結(jié)果不同
2. 如果2個(gè)子類中都繼承了父類,當(dāng)在子類中通過父類名調(diào)用時(shí),parent被執(zhí)行了2次
3. 如果2個(gè)子類中都繼承了父類,當(dāng)在子類中通過super調(diào)用時(shí),parent被執(zhí)行了1次
3. 單繼承中super
print("******單繼承使用super().__init__ 發(fā)生的狀態(tài)******") class Parent(object): def __init__(self, name): print('parent的init開始被調(diào)用') self.name = name print('parent的init結(jié)束被調(diào)用') class Son1(Parent): def __init__(self, name, age): print('Son1的init開始被調(diào)用') self.age = age super().__init__(name) # 單繼承不能提供全部參數(shù) print('Son1的init結(jié)束被調(diào)用') class Grandson(Son1): def __init__(self, name, age, gender): print('Grandson的init開始被調(diào)用') super().__init__(name, age) # 單繼承不能提供全部參數(shù) print('Grandson的init結(jié)束被調(diào)用') gs = Grandson('grandson', 12, '男') print('姓名:', gs.name) print('年齡:', gs.age) #print('性別:', gs.gender) print("******單繼承使用super().__init__ 發(fā)生的狀態(tài)******\n\n")
總結(jié)
- super().__init__相對于類名.init,在單繼承上用法基本無差
- 但在多繼承上有區(qū)別,super方法能保證每個(gè)父類的方法只會執(zhí)行一次,而使用類名的方法會導(dǎo)致方法被執(zhí)行多次,具體看前面的輸出結(jié)果
- 多繼承時(shí),使用super方法,對父類的傳參數(shù),應(yīng)該是由于python中super的算法導(dǎo)致的原因,必須把參數(shù)全部傳遞,否則會報(bào)錯(cuò)
- 單繼承時(shí),使用super方法,則不能全部傳遞,只能傳父類方法所需的參數(shù),否則會報(bào)錯(cuò)
- 多繼承時(shí),相對于使用類名.__init__方法,要把每個(gè)父類全部寫一遍,
- 而使用super方法,只需寫一句話便執(zhí)行了全部父類的方法,這也是為何多繼承需要全部傳參的一個(gè)原因
小試牛刀(以下為面試題)
以下的代碼的輸出將是什么? 說出你的答案并解釋。
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)
答案, 以上代碼的輸出是:
使你困惑或是驚奇的是關(guān)于最后一行的輸出是 3 2 3 而不是 3 2 1。為什么改變了 Parent.x 的值還會改變 Child2.x
的值,但是同時(shí) Child1.x 值卻沒有改變?
這個(gè)答案的關(guān)鍵是,在 Python中,類變量在內(nèi)部是作為字典處理的。如果一個(gè)變量的名字沒有在當(dāng)前類的字典中發(fā)現(xiàn),將搜索祖先類(比如父類)直到被引用的變量名被找到(如果這個(gè)被引用的變量名既沒有在自己所在的類又沒有在祖先類中找到,會引發(fā)一個(gè) AttributeError 異常 )。
因此,在父類中設(shè)置 x = 1 會使得類變量 x 在引用該類和其任何子類中的值為 1。這就是因?yàn)榈谝粋€(gè) print 語句的輸出是 1 1 1。
隨后,如果任何它的子類重寫了該值(例如,我們執(zhí)行語句 Child1.x = 2),然后,該值僅僅在子類中被改變。這就是為什么第二個(gè)print 語句的輸出是 1 2 1。
最后,如果該值在父類中被改變(例如,我們執(zhí)行語句 Parent.x =
3),這個(gè)改變會影響到任何未重寫該值的子類當(dāng)中的值(在這個(gè)示例中被影響的子類是 Child2)。這就是為什么第三個(gè) print 輸出是 3 2 3。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python中xml和dict格式轉(zhuǎn)換的示例代碼
最近在做APP的接口,遇到XML格式的請求數(shù)據(jù),費(fèi)了很大勁來解決,下面小編給大家分享下Python中xml和dict格式轉(zhuǎn)換問題,感興趣的朋友跟隨小編一起看看吧2019-11-11scipy.interpolate插值方法實(shí)例講解
這篇文章主要介紹了scipy.interpolate插值方法介紹,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12python實(shí)現(xiàn)支持目錄FTP上傳下載文件的方法
這篇文章主要介紹了python實(shí)現(xiàn)支持目錄FTP上傳下載文件的方法,適用于windows及Linux平臺FTP傳輸文件及文件夾,需要的朋友可以參考下2015-06-06一個(gè)基于flask的web應(yīng)用誕生 用戶注冊功能開發(fā)(5)
一個(gè)基于flask的web應(yīng)用誕生第五篇,這篇文章主要介紹了用戶注冊功能開發(fā),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04詳解Python 使用 selenium 進(jìn)行自動(dòng)化測試或者協(xié)助日常工作
這篇文章主要介紹了Python 使用 selenium 進(jìn)行自動(dòng)化測試 或者協(xié)助日常工作,我們可以使用 selenium 來幫助我們進(jìn)行自動(dòng)化的 Web 測試,也可以通過 selenium 操作瀏覽器做一些重復(fù)的,簡單的事情,來減輕我們的工作2021-09-09