Python 對多繼承以及super的一些了解

Python支持多繼承,與C++一樣都會出現(xiàn)一種問題:子類繼承的多個父類又繼承了同一個父類,這時就有可能會出現(xiàn)父類構(gòu)造方法被調(diào)用多次的情況。關(guān)于這個問題,我找了一些資料,雖然沒有親自全部驗證,這里我總結(jié)一下自己對這個問題的看法。
Python和C++的關(guān)于這個問題的解決方案不太一樣,當(dāng)然Python還要看它的版本。
C++用的方案是引入了虛繼承的語法避免同一個類被構(gòu)造了多次。
Python用的方法是MRO(method resolution order,方法解析順序) 。在在Python2.3之前,MRO的實現(xiàn)是基于DFS的,而在Python2.3以后MRO的實現(xiàn)是基于C3算法。找到的資料解釋了一下更換算法的原因:
為什么采用C3算法  
C3算法最早被提出是用于Lisp的,應(yīng)用在Python中是為了解決原來基于深度優(yōu)先搜索算法不滿足本地優(yōu)先級,和單調(diào)性的問題。
  本地優(yōu)先級:指聲明時父類的順序,比如C(A,B),如果訪問C類對象屬性時,應(yīng)該根據(jù)聲明順序,優(yōu)先查找A類,然后再查找B類。
  單調(diào)性:如果在C的解析順序中,A排在B的前面,那么在C的所有子類里,也必須滿足這個順序。
------------------------------新式類和舊式類中查找屬性的順序不同--------------------------
  在新式類中,查找一個要調(diào)用的函數(shù)或者屬性的時候,是廣度優(yōu)先搜搜的。
  在舊式類當(dāng)中,是深度優(yōu)先搜索的。如下圖所示:
  來一個例子:

# -*- coding:utf-8 -*-

class D(object):
    def foo(self):
        print "class D"

class B(D):
    pass

class C(D):
    def foo(self):
        print "class C"

class A(B, C):
    pass

f = A()
f.foo()

例子中定義D類的時候,D是新式類,所以D的所有子類都是新式類。
  A的實例對象f在調(diào)用foo函數(shù)的時候,根據(jù)廣度優(yōu)先搜索原則,調(diào)用的是C類里面的foo函數(shù)。
  上面的代碼輸出class C
  如果定義D類的時候直接class D,而不是class D(object),那么上述代碼就該輸出class D了。

如果我用的是super來解決多繼承的初始化問題的話,那么到底是怎么初始化的呢?
  這是我一開始想到的一個問題:

class A(object):
    def __init__(self,a):
        print a
        
class B(object):
    def __init__(self,a,b):
        print a+b
        
class C(A,B):
    def __init__(self):
         super(C,self).__init__(?)

obj = C()

第十一行的那個'?'的位置到底是填是什么進去才對呢?
  我一開始認(rèn)為因為是多繼承多以需要初始化父類的時候A,B都需要初始化,那么問題來了,super(C,self).init(?)怎么寫?
  我試了一下:
 ?、?? = 1      --> 輸出1
 ?、?? = 1,2     --> TypeError: init() takes exactly 2 arguments (3 given)
  定義C的時候改成class(B,A)
 ?、?? = 1      --> TypeError: init() takes exactly 3 arguments (2 given)
 ?、?? =1,2     --> 輸出3

再來看另一段代碼:

class A(object):
    def func(self):
        print 1
         
class B(object):
    def __init__(self):
        print 2
        
class C(A,B):
    def __init__(self):
         super(C,self).__init__()

obj = C()   
#The output is 3

說明什么問題?在調(diào)用super(classname,self).init()的時候應(yīng)該調(diào)用在繼承的父類列表里面有實現(xiàn)init()這個方法而且最靠左邊的那個父類的構(gòu)造方法,而且這個init(?)的'?'一定要與父類列表的里面第一個有構(gòu)造方法的父類的構(gòu)造方法簽名一樣才可以。

所以如果需要對所有父類都進行一遍初始化,還是使用類通過類名調(diào)用未綁定的初始化方法好(我說這一句話是因為我還不是很了解super)。
說一下super的使用:super( classname,對象(一般情況是self) ) 返回的是一個super對象,你可以把它當(dāng)作父類列表里面有實現(xiàn)init()這個方法而且最靠左邊的那個父類的一個對象就可以了。

參考文章地址:
    http://blog.csdn.net/imzoer/article/details/8737642
    http://blog.csdn.net/zyflying/article/details/8636006

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容