1. 程式人生 > >Python多重繼承之菱形繼承

Python多重繼承之菱形繼承

繼承是面向物件程式設計的一個重要的方式,通過繼承,子類就可以擴充套件父類的功能。在python中一個類能繼承自不止一個父類,這叫做python的多重繼承(Multiple Inheritance )。

語法

class SubclassName(BaseClass1, BaseClass2, BaseClass3, ...):
    pass

菱形繼承

在多層繼承和多繼承同時使用的情況下,就會出現複雜的繼承關係,多重多繼承。

其中,就會出現菱形繼承。如下圖所示。

在這種結構中,在呼叫順序上就出現了疑惑,呼叫順序究竟是以下哪一種順序呢

  • D->B->A->C(深度優先)
  • D->B->C->A(廣度優先)

下面我們來解答下這個問題。

舉個例子來看下:

class A():
    def __init__(self):
        print('init A...')
        print('end A...')

class B(A):
    def __init__(self):
        print('init B...')
        A.__init__(self)
        print('end B...')

class C(A):
    def __init__(self):
        print('init C...')
        A.__init__(self)
        print('end C...')

class D(B, C):
    def __init__(self):
        print('init D...')
        B.__init__(self)
        C.__init__(self)
        print('end D...')

if __name__ == '__main__':
    D()

輸出結果

init D...
init B...
init A...
end A...
end B...
init C...
init A...
end A...
end C...
end D...

從輸出結果中看,呼叫順序為:D->B->A->C->A。可以看到,B、C共同繼承於A,A被呼叫了兩次。A沒必要重複呼叫兩次。

其實,上面問題的根源都跟MRO有關,MRO(Method Resolution Order)也叫方法解析順序,主要用於在多重繼承時判斷調的屬性來自於哪個類,其使用了一種叫做C3的演算法,其基本思想時在避免同一類被呼叫多次的前提下,使用廣度優先和從左到右的原則去尋找需要的屬性和方法。

那麼如何避免頂層父類中的某個方法被多次呼叫呢,此時就需要super()來發揮作用了,super本質上是一個類,內部記錄著MRO資訊,由於C3演算法確保同一個類只會被搜尋一次,這樣就避免了頂層父類中的方法被多次執行了,上面程式碼可以改為:

class A():
    def __init__(self):
        print('init A...')
        print('end A...')

class B(A):
    def __init__(self):
        print('init B...')
        super(B, self).__init__()
        print('end B...')

class C(A):
    def __init__(self):
        print('init C...')
        super(C, self).__init__()
        print('end C...')

class D(B, C):
    def __init__(self):
        print('init D...')
        super(D, self).__init__()
        print('end D...')

if __name__ == '__main__':
    D()

輸出結果:

init D...
init B...
init C...
init A...
end A...
end C...
end B...
end D...

可以看出,此時的呼叫順序是D->B->C->A。即採用是廣度優先的遍歷方式。

補充內容

Python類分為兩種,一種叫經典類,一種叫新式類。都支援多繼承,但繼承順序不同。

  • 新式類:從object繼承來的類。(如:class A(object)),採用廣度優先搜尋的方式繼承(即先水平搜尋,再向上搜索)。
  • 經典類:不從object繼承來的類。(如:class A()),採用深度優先搜尋的方式繼承(即先深入繼承樹的左側,再返回,再找右側)。

Python2.x中類的是有經典類和新式類兩種。Python3.x中都是新式類。

開啟微信掃一掃,關注【西加加先生】微信公眾號,及時接收博文推送。

相關推薦

Python多重繼承菱形繼承

繼承是面向物件程式設計的一個重要的方式,通過繼承,子類就可以擴充套件父類的功能。在python中一個類能繼承自不止一個父類,這叫做python的多重繼承(Multiple Inheritance )。 語法 class SubclassName(BaseClass1, BaseClass2, BaseClas

[擴充套件閱讀] 多重繼承的陷阱:鑽石繼承菱形繼承)問題

支援多繼承的面向物件程式設計都可能會導致鑽石繼承(菱形繼承)問題,看以下程式碼: class A(): def __init__(self): print("進入A…") print("離開A…") class B(A):

C++記憶體分佈菱形繼承(無虛擬函式)

       菱形繼承的定義是:兩個子類繼承同一父類,而又有子類同時繼承這兩個子類。例如a,b兩個類同時繼承c,但是又有一個d類同時繼承a,b類。探究的過程還是很有趣的。 菱形繼承的記憶體佈局探究花了我幾天時間,探究起來還是有點難度的。博文中如果有錯誤的地方,歡迎大家指正,

C++菱形繼承

    當我們談C++時,我們談些什麼?    封裝,繼承,多型。這是C++語言的三大特性,而每次在談到繼承時我們不可避免的要談到一個很重要的問題——菱形繼承。a.菱形繼承是什麼    如上圖,菱形繼承

多重繼承的陷阱:鑽石繼承菱形繼承)問題

支援多繼承的面向物件程式設計都可能會導致鑽石繼承(菱形繼承)問題,看以下程式碼: class A(): def __init__(self): print("進入A…") print("離開A…") class B(A):

C++繼承匯總(單繼承、多繼承、虛繼承菱形繼承

虛基類表指針 www 地址 編譯 聲明 pre 繼承 第一個 src 一、C++中的對象模型 1、 概念 語言中直接支持面向對象程序設計的部分; 對於各種支持的底層實現機制。(沒看懂……) 2、 類中的成員分類 a) 成員函數   i. static function   

繼承與派生(4):二義性(三角繼承菱形繼承

         一般說來,在派生類中對基類成員的訪問應該是唯一的,但是,由於多繼承情況下,可能造成對基類中某成員的訪問出現了不唯一的情況,則稱為對基類成員訪問的二義性問題。  實際上,在上例已經出現過這一問題,回憶一下上例中(參照繼承

JS繼承寄生繼承

JavaScript繼承還有一種繼承模式——寄生繼承。 舉個例子: function object(o) { function F() {}; F.prototype = o; return new F(); } var twoD = { name: '2D shape

JS繼承原型繼承

在繼承時,出於效率的考慮,我們會盡可能地將一些可重用的屬性和方法新增到原型中去,如果如此,我們就可以僅依靠原型就完成繼承關係的構建。 function Shape() {} Shape.prototype.name = 'shape'; Shape.prototype.toStrin

JS繼承組合繼承

前面介紹了原型鏈繼承以及建構函式繼承,它們都有各自的優缺點 特點 優點 缺點 原型鏈繼承 子類原型prototype對父類例項化來實現 子類不僅僅可以訪問父類原型上的

【C++】c++單繼承、多繼承菱形繼承記憶體佈局(虛擬函式表結構)

單繼承:只有一個基類和一個派生類 class Base { public: virtual void fun1() { cout << "Base::func1()" << endl;

c++單繼承、多繼承菱形繼承的記憶體佈局(虛擬函式表結構)

單繼承:只有一個基類和一個派生類 class Base { public: virtual void fun1() { cout << "Base::func1()" << endl; } vir

C++中的多型、單繼承、多繼承菱形繼承菱形虛擬繼承

C++中的繼承體系,有單繼承、多繼承、菱形繼承、菱形虛擬繼承,以及各型別的物件模型,我們今天做一個簡單的剖析 (1)什麼多型? 所謂多型,就是“多種形態”。在面向物件的方法中一般是這樣描述多型的:向不同的物件傳送同一個訊息,不同的物件在接收時會產生不同的行為(即方法)。 多

C++繼承(單繼承、多繼承菱形繼承)記憶體模型的深入研究

繼承的概念:繼承機制:可以利用已有的資料型別來定義新的資料型別,所定義的新的資料型別不僅擁有新定義的成員,而且還同時擁有舊的成員。OOP強調軟體的可重用性(software reuseablility)

C++繼承菱形繼承

繼承是⾯向物件復⽤的重要⼿段。 通過繼承定義⼀個類,繼承是型別之間的關係建模,共享公有的東西,實現各⾃本質不同的東西。 我們類成員訪問限定符有三種: public(公有),protected(保護),private(私有) 我們的繼承關係也有三種: p

c++單繼承、多繼承菱形繼承記憶體佈局(虛擬函式表結構)

單繼承:只有一個基類和一個派生類 class Base { public: virtual void fun1() { cout << "Base::func1()" << endl; } vir

python繼承中組合用法與菱形繼承關係查詢法

1.什麼是組合    組合就是一個類的物件具備某一屬性,該屬性的值是指向另外外一個類的物件2.為什麼用組合    組合也是用來解決類與類之間程式碼冗餘問題3.用法class Course:                       #組合 def __init__(self

Python 多重繼承

python 多重繼承 #!/usr/bin/env python# -*- coding:utf-8 -*-# author: Changhua Gongclass person(object): def __init__(self, name): self.name = nam

Python全棧路系列---------面向對象4接口與抽象,多繼承與多態)

統一 dog blog 水果 創建 設計 概念 fly 支付 接口類與抽像類 在python中,並沒有接口類這種東西,即便不通過專門的模塊定義接口,我們也應該有一些基本的概念 編程思想 歸一化設計:  1.接口類 不實現具體的方法,並且可以多繼承  2.抽象類 可以做一

Python多重繼承引發的問題——牛逼的super

ont 這就是 ans lin 技術 wid 然而 多重繼承 obj 少說廢話多做事先上一個圖,此圖用win7下的畫圖工具所畫,當然,這不是重點 需要清楚的一個事情是: 任何類,都默認並隱式的繼承object類(根類),在上面的圖中,Transf