多繼承以及MRO順序

2021-08-26 02:27:37 字數 4829 閱讀 1875

單獨呼叫父類的方法

print(「*多繼承使用類名.init發生的狀態*「)

class parent(object):

definit(self, name):

print(『parent的init開始被呼叫』)

self.name = name

print(『parent的init結束被呼叫』)

class son1(parent):

definit(self, name, age):

print(『son1的init開始被呼叫』)

self.age = age

parent.init(self, name)

print(『son1的init結束被呼叫』)

class son2(parent):

definit(self, name, gender):

print(『son2的init開始被呼叫』)

self.gender = gender

parent.init(self, name)

print(『son2的init結束被呼叫』)

class grandson(son1, son2):

definit(self, name, age, gender):

print(『grandson的init開始被呼叫』)

son1.init(self, name, age) # 單獨呼叫父類的初始化方法

son2.init(self, name, gender)

print(『grandson的init結束被呼叫』)

gs = grandson(『grandson』, 12, 『男』)

print(『姓名:』, gs.name)

print(『年齡:』, gs.age)

print(『性別:』, gs.gender)

print(「*多繼承使用類名.init發生的狀態*\n\n」)

執行結果:

*多繼承使用類名.init發生的狀態*

grandson的init開始被呼叫

son1的init開始被呼叫

parent的init開始被呼叫

parent的init結束被呼叫

son1的init結束被呼叫

son2的init開始被呼叫

parent的init開始被呼叫

parent的init結束被呼叫

son2的init結束被呼叫

grandson的init結束被呼叫

姓名: grandson

年齡: 12

性別: 男

*多繼承使用類名.init發生的狀態*

2. 多繼承中super呼叫有所父類的被重寫的方法

print(「*多繼承使用super().init發生的狀態*「)

class parent(object):

definit(self, name, *args, **kwargs): # 為避免多繼承報錯,使用不定長引數,接受引數

print(『parent的init開始被呼叫』)

self.name = name

print(『parent的init結束被呼叫』)

class son1(parent):

definit(self, name, age, *args, **kwargs): # 為避免多繼承報錯,使用不定長引數,接受引數

print(『son1的init開始被呼叫』)

self.age = age

super().init(name, *args, **kwargs) # 為避免多繼承報錯,使用不定長引數,接受引數

print(『son1的init結束被呼叫』)

class son2(parent):

definit(self, name, gender, *args, **kwargs): # 為避免多繼承報錯,使用不定長引數,接受引數

print(『son2的init開始被呼叫』)

self.gender = gender

super().init(name, *args, **kwargs) # 為避免多繼承報錯,使用不定長引數,接受引數

print(『son2的init結束被呼叫』)

class grandson(son1, son2):

definit(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().init發生的狀態*

(print(「*單繼承使用super().init發生的狀態*\n\n」)

總結 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)

child1.x = 2

print(parent.x, child1.x, child2.x)

parent.x = 3

print(parent.x, child1.x, child2.x)

答案, 以上**的輸出是:

1 1 1

1 2 1

3 2 3

使你困惑或是驚奇的是關於最後一行的輸出是 3 2 3 而不是 3 2 1。為什麼改變了 parent.x 的值還會改變 child2.x 的值,但是同時 child1.x 值卻沒有改變?

這個答案的關鍵是,在 python 中,類變數在內部是作為字典處理的。如果乙個變數的名字沒有在當前類的字典中發現,將搜尋祖先類(比如父類)直到被引用的變數名被找到(如果這個被引用的變數名既沒有在自己所在的類又沒有在祖先類中找到,會引發乙個 attributeerror 異常 )。

因此,在父類中設定 x = 1 會使得類變數 x 在引用該類和其任何子類中的值為 1。這就是因為第乙個 print 語句的輸出是 1 1 1。

隨後,如果任何它的子類重寫了該值(例如,我們執行語句 child1.x = 2),然後,該值僅僅在子類中被改變。這就是為什麼第二個 print 語句的輸出是 1 2 1。

最後,如果該值在父類中被改變(例如,我們執行語句 parent.x = 3),這個改變會影響到任何未重寫該值的子類當中的值(在這個示例中被影響的子類是 child2)。這就是為什麼第三個 print 輸出是 3 2 3。

多繼承以及MRO順序

個類同時繼承多個類,稱為多繼承。class 類名 類名1,類名2 多繼承關係中,當多個 類具有同名的成員,類調時該成員時先調 繼承關係中的第 個宣告的類的成員。多繼承指的是子類繼承多個父類,可以通過三種方式訪問父類的方法 1 父類名.父類方法 self 這種方式容易造成父類方法被呼叫多次的問題 菱形...

RUN IT 多繼承以及MRO順序

多繼承指的是子類繼承多個父類,可以通過三種方式訪問父類的方法 父類名.父類方法 self 這種方式容易造成父類方法被呼叫多次的問題,而且父類名稱發生變化,子類呼叫的地方都需要修改。super 指定某個類名,self 父類方法 從指定類名的mro下一級開始呼叫 super 父類方法 按照mro上級父類...

多繼承及MRO順序

super init 相對於類名.init,在單繼承上用法基本 差 但在多繼承上有區別,super方法能保證每個父類的方法只會執行一次,而使用類名的方法會導致方法被執行多次 多繼承時,使用super方法,對父類的傳引數,應該是由於python中 super的演算法導致的原因,必須把引數全部傳遞,否則...