super在多繼承中的呼叫細節

2021-09-02 16:18:26 字數 2613 閱讀 3950

注:此處以python 3為執行環境,例子摘自《python cookbook》第8章。

python中若子類要實現父類的初始化,主要有兩種方法,第一種是直接通過父類名,第二種是利用super方法。在單繼承時兩者沒什麼區別,但在多繼承時就需要注意一些細微的差距了。例項解釋才是硬道理!

1、利用父類名的情況:

class base:

def __init__(self):

print('base.__init__')

class a(base):

def __init__(self):

base.__init__(self)

print('a.__init__')

class b(base):

def __init__(self):

base.__init__(self)

print('b.__init__')

class c(a,b):

def __init__(self):

a.__init__(self)

b.__init__(self)

print('c.__init__')

此時例項化c類會輸出如下:

>>> c = c()

base.__init__

a.__init__

base.__init__

b.__init__

c.__init__

>>>

從中可看出base類被呼叫了兩次。這想必在很多情況下都不是我們想要的結果,所以此時可考慮用super方法。

2、利用super的情況:

class base:

def __init__(self):

print('base.__init__')

class a(base):

def __init__(self):

super().__init__()

print('a.__init__')

class b(base):

def __init__(self):

super().__init__()

print('b.__init__')

class c(a,b):

def __init__(self):

super().__init__() # only one call to super() here

print('c.__init__')

此時再例項化c類的輸出為:

>>> c = c()

base.__init__

b.__init__

a.__init__

c.__init__

>>>

可看出base類是不是只呼叫了一次啊!但很遺憾的是,這並不是促使我寫這篇部落格記錄的原因,因為如果仔細觀察的話,雖說base類的確如預期只呼叫了一次,但你有沒有發覺是先輸出「b.__init__」而後才輸出的「a.__init__」?而且為什麼這樣就使得base只初始化了一次?想必你也有點懵逼了吧?其實這一切都得「怪罪」於super在多繼承時的呼叫過程。python在實現乙個類(不僅是繼承)時,會產生乙個方法生成解析順序列表,該列表可通過類屬性 __mro__ 檢視之,如本例中是這樣的:

>>> c.__mro__

(, , ,

, )>>>

所以在搜尋乙個屬性或方法時,它就會按照這個列表遍歷每個類,直到找到第乙個匹配這個屬性或方法的類為止。而[color=red]在繼承中使用super時,直譯器會每遇到一次super就會在該列表上搜尋下乙個類,直到不再遇到super或列表遍歷完為止,然後再類似遞迴逐層返回。[/color]因此本例中搜尋過程為:c中遇到super --> 搜尋列表中的下乙個類,即a --> a中再次遇到super,搜尋b --> b中super再現,搜尋base --> 初始化base類,遞迴返回。

為了更好的解釋該過程,現在請注釋掉b類的super所在行:

class b(base):

def __init__(self):

#super().__init__()

print('b.__init__')

class c(a,b):

def __init__(self):

super().__init__() # only one call to super() here

print('c.__init__')

再次例項化c類,輸出如下:

>>> c = c()

b.__init__

a.__init__

c.__init__

base類不再產生輸出!為什麼?因為b中沒了super後,就阻斷了列表去搜尋base類,所以也就沒有初始化base了!

Python中的多繼承和super

簡單,定義四個類,a,b,c,d,其中d繼承自b和c,而b,c繼承自a,從第一步開始看 classa defrun self 第五步,列印如下print語句,此時self也是d類的例項物件 print f a哈哈 class b a def run self 第三步,首先列印print語句,此時se...

Python中多繼承與super 用法

python類分為兩種,一種叫經典類,一種叫新式類。兩種都支援多繼承。考慮一種情形,b繼承於a,c繼承於a和b,但c需要呼叫父類的init 函式時,前者會導致父類a的init 函式被呼叫2次,這是不希望看到的。而且子類要顯式地指定父類,不符合dry原則。經典類 class a def init se...

Python 多繼承中的super 與MRO

繼承 單繼承 父類 class animal object docstring for animal def init self,name self.name name def run self print is running format self.name def eat self print...