談談 python 面向對象中的多重繼承

2022-01-08 Crossin的編程教室
什麼是多重繼承

繼承是面向對象編程的一個重要的方式 ,通過繼承 ,子類就可以擴展父類的功能 。和 c++ 一樣 ,在 python 中一個類能繼承自不止一個父類 ,這叫做 python 的多重繼承(Multiple Inheritance )。多重繼承的語法與單繼承類似 。

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

當然 ,子類所繼承的所有父類同樣也能有自己的父類 ,這樣就可以得到一個繼承關係機構圖如下圖所示 :

鑽石繼承(菱形繼承)問題

多重繼承容易導致鑽石繼承(菱形繼承)問題 ,關於為什麼會叫做鑽石繼承問題 ,看下圖就知道了 :

在 python 中 ,鑽石繼承首先體現在父類方法的調用順序上 ,比如若B和C同時重寫了 A 中的某個方法時 :

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")

class C(A):
    def m(self):
        print("m of C called")

class D(B,C):
    pass

如果我們實例化 D 為 d ,然後調用 d.m() 時 ,會輸出 "m of B called",如果 B 沒有重寫 A 類中的 m 方法時 :

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    pass

class C(A):
    def m(self):
        print("m of C called")

class D(B,C):
    pass

此時調用 d.m 時,則會輸出 "m of C called" , 那麼如何確定父類方法的調用順序呢 ,這一切的根源還要講到方法解析順序(Method Resolution Order,MRO),這一點我們等會再將。

鑽石繼承還有一個問題是 ,比如若 B 和 C 中的 m 方法也同時調用了 A 中的m方法時 :

class A:
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        A.m(self)

class C(A):
    def m(self):
        print("m of C called")
        A.m(self)

class D(B,C):
    def m(self):
        print("m of D called")
        B.m(self)
        C.m(self)

此時我們調用 d.m ,A.m 則會執行兩次。

m of D called
m of B called
m of A called
m of C called
m of A called

這種問題最常見於當我們初始化 D 類時 ,那麼如何才能避免鑽石繼承問題呢 ?

super and MRO

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

比如針對如下的代碼 :

>>> class F(object): pass
>>> class E(object): pass
>>> class D(object): pass
>>> class C(D,F): pass
>>> class B(D,E): pass
>>> class A(B,C): pass

當你列印 A.__mro__ 時可以看到輸出結果為 :

(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)

如果我們實例化 A 為 a 並調用 a.m() 時 ,如果 A 中沒有 m 方法 ,此時python 會沿著 MRO 表逐漸查找 ,直到在某個父類中找到m方法並執行 。

那麼如何避免頂層父類中的某個方法被執行多次呢 ,此時就需要super()來發揮作用了 ,super 本質上是一個類 ,內部記錄著 MRO 信息 ,由於 C3 算法確保同一個類只會被搜尋一次 ,這樣就避免了頂層父類中的方法被多次執行了 ,比如針對鑽石繼承問題 2 中的代碼可以改為 :

class A(object):
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        super().m()

class C(A):
    def m(self):
        print("m of C called")
        super().m()

class D(B,C):
    def m(self):
        print("m of D called")
        super().m()

此時列印的結果就變成了 :

m of D called
m of B called
m of C called
m of A called

結論

多重繼承問題是個坑 ,很多程式語言中並沒有多重繼承的概念 ,畢竟它帶來的麻煩比能解決的問題都要多 ,所以如果不是特別必要 ,還是儘量少用多重繼承 。如果你非要用 ,那你要好好研究下類的層次結構 ,至少要對 C3 算法具有一定的了解吧 ,比如弄懂下面的代碼哪裡出了問題 ?

>>> F=type('Food',(),{'remember2buy':'spam'})
>>> E=type('Eggs',(F,),{'remember2buy':'eggs'})
>>> G=type('GoodFood',(F,E),{}) 
# TypeError: Cannot create a consistent method resolution
# order (MRO) for bases Food, Eggs

相關焦點

  • python | 關於多重繼承那些事
    什麼是多重繼承繼承是面向對象編程的一個重要的方式 ,通過繼承 ,子類就可以擴展父類的功能 。和 c++ 一樣 ,在 python 中一個類能繼承自不止一個父類 ,這叫做 python 的多重繼承(Multiple Inheritance )。多重繼承的語法與單繼承類似 。
  • python面向對象三大特徵
    大概所有變成初學者初學者最頭疼的第一道坎就是面向對象的理解封裝從封裝本身去理解 就是把小貓小狗用袋子裝起來,然後把袋子的小口封上私有化方法:方法的私有化可以保護好一些核心的代碼,可以添加條件,是別人不能不滿足條件的更改,進行代碼的保護,python
  • 好好理解 Python 面向對象中的多繼承和super
    ok,以下是 VIP 基礎階段的試看文:Python快速入門 | 好好理解 Python 面向對象中的多繼承和super咱們上一篇講到了繼承,說到了子類和父類之間的關係,父類也叫作基類、超類,也就是 super class ,上次我們說要在子類使用父類定義的東西,就需要用到 super 方法,有些朋友不太理解:不是說子類繼承了父類,就直接都擁有了父類的東西了麼
  • 當心掉進Python多重繼承裡的坑
    這是菜鳥學python的第42篇原創文章閱讀本文大概需要11分鐘關於類的知識點裡面,有一塊是關於多重繼承
  • python(15):面向對象<1>:類的三大特徵
    一、了解什麼是類1.定義一個簡單的類在Python中,類通過 class 關鍵字定義,類名通用習慣為首字母大寫,Python3中類基本都會繼承於object
  • 從零入門量化交易系列-python的面向對象
    1、面向對象基礎概念類(Class): 用來描述具有相同屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。
  • 手把手Java入門:繼承(面向對象篇)
    繼承的概念繼承是java面向對象編程中的基石,它允許創建分層次的類。繼承是子類繼承父類的特徵和行為,使得子類對象具有父類的實例域和方法,或者子類直接繼承父類的方法,使得子類具有父類相同的行為。生活中的繼承老鼠和貓都是動物類,老鼠和貓就是動物類的子類,而動物類就是父類,繼承的符合關係是:is-a.在java中實現繼承的關鍵字是extends,它可以聲明一個類是從另外一個類繼承而來的。
  • 如何理解 Python 中的面向對象編程?
    現如今面向對象編程的使用非常廣泛,本文我們就來探討一下Python中的面向對象編程。
  • 使用Python Super()為類提供繼承支持
    深入super()多重繼承中的super()多重繼承概述方法解析順序多重繼承替代方案super()回顧雖然Python不是一種純面向對象的語言,但它足夠靈活,功能強大,足以讓您使用面向對象的範例構建應用程式。 Python實現這一目標的方法之一是通過使用super()來支持繼承。
  • 【4】類的繼承和多態-簡易的Python面向對象教程
    前言 面向對象是所有高級語言(Python,Java,C++等)的基石,是重中之重。 這個文章系列的目的是通過簡單易懂的例子,深入淺出,讓Python學習者牢固的掌握Python面向對象的概念和方法。
  • Python入門基礎之面向對象二:類和實例、方法
    前面一篇文章我介紹了python面向對象的基本知識,連結在最下面。初步解釋了面向對象和面向對象的優點,今天就開始正式用代碼來展現面向對象。1、利用class創建類Python中,創建類的語句是如下所示先解釋一下,class後面跟的是類名,括號裡面是基類(也成為父類)python3中默認繼承object。
  • 如何理解python中的類和對象?
    什麼是類和對象類和對象,在我們的生活中其實是很容易找例子的。類是一種把對象分組歸類的方法。比如動物,植物就可以看作是類,而大象,獅子就可以看作一個動物類中的對象;花,草可以看作是植物類中的對象。為什麼大象和獅子就劃分為動物類,花和草就劃分為植物類呢?
  • opencv-python獲取圖像:面向對象與面向過程
    下面是分別用面向過程與面向對象的編程方法實現讀取本地圖像和打開攝像頭兩段代碼:# -*- coding: utf-8 -*-"""面向過程的編程方法,用函數把解決問題的步驟一步一步實現。運行環境:win10系統 python==3.6 opencv-contrib-python== 4.1.0第一行「# -*- coding: utf-8 -*-」 告訴Python解釋器,按照UTF-8編碼讀取原始碼"""import
  • python核心部分創建對象中各種名詞的定義及用法
    但是python被稱為面向對象的語言,所以創建對象才是python的核心部分,我們今天就走進python的核心部分-創建對象。接下來幾天的章節非常重要非常核心,非常重要非常核心,非常重要非常核心,重要的事情說是三次。首先說一下幾個名詞的定義,方便你在以後的學習中理解。
  • python中類的繼承和多態
    繼承是為了代碼復用和設計復用而設計的,是面向對象程序設計的重要特徵之一。當我們設計一個新類時,如果可以繼承一個已有的設計良好的類然後進行二次開發,無疑會大幅度減少開發工作量。1.類的繼承類繼承語法:Class 派生類名(基類名): #基類名寫在括號裡派生類成員在繼承關係中,已有的,設計好的類稱為父類或基類,新設計的類稱為子類或派生類。派生類可以繼承父類的公有成員,但是不能繼承其私有成員。
  • C 語言面向對象編程 - 繼承
    上一篇文章主要講述了 C 語言面向對象編程
  • Python中的類繼承
    歡迎關注 「小白玩轉Python」,發現更多 「有趣」繼承是面向對象編程中的一個概念,現有的類可以被一個新的類修改。現有的類稱為基類,新類稱為派生類。在本文中,我們將討論python中的類繼承。讓我們開始吧!
  • Python面向對象編程的基本概念
    之後,這種編程技術已被包括Python在內的各種程式語言所採用,如今它的應用幾乎遍及各個領域,例如實時系統,人工智慧和專家系統,客戶端伺服器系統,面向對象的資料庫以及許多其他領域。更多。因此,在本文中,我將解釋Python中的面向對象編程的基本概念。表中的內容什麼是面向對象的編程?
  • 面向對象特性之三:多態(Python進階教程)
    今天我們要講一講面向對象的第三個特性:多態;什麼叫做多態?從字面意思上理解,就是一個函數具有多種形態。本質上其實就是同一操作方法作用於不同的對象時,有著不同的解釋,執行不同的邏輯,產生不同的結果。這兩個類是「部門類」的子類,下面我們用代碼來表示一下這三個類:在上例中,我們定義了三個類,主類叫做「部門類」,兩個子類繼承於該類,分別代表「海運部門」和「空運部門」,這兩個類除了都有自己的構造函數之外,還有著一個具有相同名稱的方法,我們暫且叫做「送貨」方法。
  • PHP面向對象
    編程思想有面向過程和面向對象面向過程:編程思路集中的是過程上面向對象:編程思路集中在參與的對象上2  面向對象的好處多人合作方便減少代碼冗餘,靈活性高代碼的可重用性發揮到極致可擴展性強多學一招:OOP:面向對象編程(Object Oriented Programming,面向對象編程)OOA: 面向對象分析(Object-Oriented