1. 程式人生 > >Python 封裝,繼承 和多繼承

Python 封裝,繼承 和多繼承

繼承

目標

  • 單繼承
  • 多繼承

面向物件三大特性

  1. 封裝 根據 職責屬性方法 封裝 到一個抽象的
  2. 繼承 實現程式碼的重用,相同的程式碼不需要重複的編寫
  3. 多型 不同的物件呼叫相同的方法,產生不同的執行結果,增加程式碼的靈活度

01. 單繼承

1.1 繼承的概念、語法和特點

繼承的概念子類 擁有 父類 的所有 方法屬性

011_繼承對比圖示

1) 繼承的語法

class 類名(父類名):

    pass
  • 子類 繼承自 父類,可以直接 享受 父類中已經封裝好的方法,不需要再次開發
  • 子類
    中應該根據 職責,封裝 子類特有的 屬性和方法

2) 專業術語

  • Dog 類是 Animal 類的子類Animal 類是 Dog 類的父類Dog 類從 Animal繼承
  • Dog 類是 Animal 類的派生類Animal 類是 Dog 類的基類Dog 類從 Animal派生

3) 繼承的傳遞性

  • C 類從 B 類繼承,B 類又從 A 類繼承
  • 那麼 C 類就具有 B 類和 A 類的所有屬性和方法

子類 擁有 父類 以及 父類的父類 中封裝的所有 屬性方法

提問

哮天犬 能夠呼叫 Cat 類中定義的 catch

方法嗎?

答案

不能,因為 哮天犬Cat 之間沒有 繼承 關係

1.2 方法的重寫

  • 子類 擁有 父類 的所有 方法屬性
  • 子類 繼承自 父類,可以直接 享受 父類中已經封裝好的方法,不需要再次開發

應用場景

  • 父類 的方法實現不能滿足子類需求時,可以對方法進行 重寫(override)

012_繼承方法的重寫

重寫 父類方法有兩種情況:

  1. 覆蓋 父類的方法
  2. 對父類方法進行 擴充套件

1) 覆蓋父類的方法

  • 如果在開發中,父類的方法實現子類的方法實現完全不同
  • 就可以使用 覆蓋 的方式,在子類中
    重新編寫 父類的方法實現

具體的實現方式,就相當於在 子類中 定義了一個 和父類同名的方法並且實現

重寫之後,在執行時,只會呼叫 子類中重寫的方法,而不再會呼叫 父類封裝的方法

2) 對父類方法進行 擴充套件

  • 如果在開發中,子類的方法實現包含 父類的方法實現
    • 父類原本封裝的方法實現子類方法的一部分
  • 就可以使用 擴充套件 的方式
    1. 在子類中 重寫 父類的方法
    2. 在需要的位置使用 super().父類方法 來呼叫父類方法的執行
    3. 程式碼其他的位置針對子類的需求,編寫 子類特有的程式碼實現
關於 super
  • Pythonsuper 是一個 特殊的類
  • super() 就是使用 super 類創建出來的物件
  • 最常 使用的場景就是在 重寫父類方法時,呼叫 在父類中封裝的方法實現
呼叫父類方法的另外一種方式(知道)

Python 2.x 時,如果需要呼叫父類的方法,還可以使用以下方式:

父類名.方法(self)
  • 這種方式,目前在 Python 3.x 還支援這種方式
  • 這種方法 不推薦使用,因為一旦 父類發生變化,方法呼叫位置的 類名 同樣需要修改

提示

  • 在開發時,父類名super() 兩種方式不要混用
  • 如果使用 當前子類名 呼叫方法,會形成遞迴呼叫,出現死迴圈

1.3 父類的 私有屬性 和 私有方法

  1. 子類物件 不能 在自己的方法內部,直接 訪問 父類的 私有屬性私有方法
  2. 子類物件 可以通過 父類公有方法 間接 訪問到 私有屬性私有方法
  • 私有屬性、方法 是物件的隱私,不對外公開,外界 以及 子類 都不能直接訪問
  • 私有屬性、方法 通常用於做一些內部的事情

示例

  • B 的物件不能直接訪問 __num2 屬性
  • B 的物件不能在 demo 方法內訪問 __num2 屬性
  • B 的物件可以在 demo 方法內,呼叫父類的 test 方法
  • 父類的 test 方法內部,能夠訪問 __num2 屬性和 __test 方法

02. 多繼承

概念

  • 子類 可以擁有 多個父類,並且具有 所有父類屬性方法
  • 例如:孩子 會繼承自己 父親母親特性

語法

class 子類名(父類名1, 父類名2...)
    pass

2.1 多繼承的使用注意事項

問題的提出

  • 如果 不同的父類 中存在 同名的方法子類物件 在呼叫方法時,會呼叫 哪一個父類中的方法呢?

提示:開發時,應該儘量避免這種容易產生混淆的情況! —— 如果 父類之間 存在 同名的屬性或者方法,應該 儘量避免 使用多繼承

Python 中的 MRO —— 方法搜尋順序(知道)

  • Python 中針對 提供了一個 內建屬性 __mro__ 可以檢視 方法 搜尋順序
  • MRO 是 method resolution order,主要用於 在多繼承時判斷 方法、屬性 的呼叫 路徑
    print(C.__mro__)

輸出結果

(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
  • 在搜尋方法時,是按照 __mro__ 的輸出結果 從左至右 的順序查詢的
  • 如果在當前類中 找到方法,就直接執行,不再搜尋
  • 如果 沒有找到,就查詢下一個類 中是否有對應的方法,如果找到,就直接執行,不再搜尋
  • 如果找到最後一個類,還沒有找到方法,程式報錯

2.2 新式類與舊式(經典)類

objectPython 為所有物件提供的 基類,提供有一些內建的屬性和方法,可以使用 dir 函式檢視

  • 新式類:以 object 為基類的類,推薦使用

  • 經典類:不以 object 為基類的類,不推薦使用

  • Python 3.x 中定義類時,如果沒有指定父類,會 預設使用 object 作為該類的 基類 —— Python 3.x 中定義的類都是 新式類

  • Python 2.x 中定義類時,如果沒有指定父類,則不會以 object 作為 基類

新式類經典類 在多繼承時 —— 會影響到方法的搜尋順序

為了保證編寫的程式碼能夠同時在 Python 2.xPython 3.x 執行!
今後在定義類時,如果沒有父類,建議統一繼承自 object

class 類名(object):
    pass