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

  Python支持多繼承,與C++同樣都會出現一種問題:子類繼承的多個父類又繼承了同一個父類,這時就有可能會出現父類構造方法被調用屢次的狀況。關於這個問題,我找了一些資料,雖然沒有親自所有驗證,這裏我總結一下本身對這個問題的見解。算法

  Python和C++的關於這個問題的解決方案不太同樣,固然Python還要看它的版本。函數

  C++用的方案是引入了虛繼承的語法避免同一個類被構造了屢次。spa

  Python用的方法是MRO(method resolution order,方法解析順序) 。在在Python2.3以前,MRO的實現是基於DFS的,而在Python2.3之後MRO的實現是基於C3算法。找到的資料解釋了一下更換算法的緣由:.net

  爲何採用C3算法
  C3算法最先被提出是用於Lisp的,應用在Python中是爲了解決原來基於深度優先搜索算法不知足本地優先級,和單調性的問題。
  本地優先級:指聲明時父類的順序,好比C(A,B),若是訪問C類對象屬性時,應該根據聲明順序,優先查找A類,而後再查找B類。
  單調性:若是在C的解析順序中,A排在B的前面,那麼在C的全部子類裏,也必須知足這個順序。
------------------------------新式類和舊式類中查找屬性的順序不一樣-------------------------------------
   在新式類中,查找一個要調用的函數或者屬性的時候,是廣度優先搜搜的。
  在舊式類當中,是深度優先搜索的。以下圖所示:
  來一個例子:
  
 1 # -*- coding:utf-8 -*-
 2 
 3 class D(object):
 4     def foo(self):
 5         print "class D"
 6 
 7 class B(D):
 8     pass
 9 
10 class C(D):
11     def foo(self):
12         print "class C"
13 
14 class A(B, C):
15     pass
16 
17 f = A()
18 f.foo()
  例子中定義D類的時候,D是新式類,因此D的全部子類都是新式類。
  A的實例對象f在調用foo函數的時候,根據廣度優先搜索原則,調用的是C類裏面的foo函數。
  上面的代碼輸出class C
  若是定義D類的時候直接class D,而不是class D(object),那麼上述代碼就該輸出class D了。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------code

 

  若是我用的是super來解決多繼承的初始化問題的話,那麼究竟是怎麼初始化的呢?對象

  這是我一開始想到的一個問題:blog

  

 1 class A(object):
 2     def __init__(self,a):
 3         print a
 4         
 5 class B(object):
 6     def __init__(self,a,b):
 7         print a+b
 8         
 9 class C(A,B):
10     def __init__(self):
11          super(C,self).__init__(?)
12 
13 obj = C()   

  第十一行的那個'?'的位置究竟是填是什麼進去纔對呢?繼承

  我一開始認爲由於是多繼承多以須要初始化父類的時候A,B都須要初始化,那麼問題來了,super(C,self).__init__(?)怎麼寫?utf-8

  我試了一下:get

  ① ? = 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

 

  再來看另外一段代碼:

 1 class A(object):
 2     def func(self):
 3         print 1
 4          
 5 class B(object):
 6     def __init__(self):
 7         print 2
 8         
 9 class C(A,B):
10     def __init__(self):
11          super(C,self).__init__()
12 
13 obj = C()   
14 #The output is 3

  說明什麼問題?在調用super(classname,self).__init__()的時候應該調用在繼承的父類列表裏面有實現__init__()這個方法並且最靠左邊的那個父類的構造方法,並且這個__init__(?)的'?'必定要與父類列表的裏面第一個有構造方法的父類的構造方法簽名同樣才能夠。

 

  因此若是須要對全部父類都進行一遍初始化,仍是使用類經過類名調用未綁定的初始化方法好(我說這一句話是由於我還不是很瞭解super)。

  說一下super的使用:

    super( classname,對象(通常狀況是self) ) 返回的是一個super對象,你能夠把它看成父類列表裏面有實現__init__()這個方法並且最靠左邊的那個父類的一個對象就能夠了。

 

  參考文章地址:

    http://blog.csdn.net/imzoer/article/details/8737642

    http://blog.csdn.net/zyflying/article/details/8636006

相關文章
相關標籤/搜索