天天看點

Python 進階_OOP 面向對象程式設計_組合與繼承前言組合派生

<a href="#%E5%89%8D%E8%A8%80">前言</a>

<a href="#%E7%BB%84%E5%90%88">組合</a>

<a href="#%E6%B4%BE%E7%94%9F">派生</a>

<a href="#%E9%80%9A%E8%BF%87%E7%BB%A7%E6%89%BF%E6%9D%A5%E8%A6%86%E7%9B%96%E9%87%8D%E8%BD%BD%E6%96%B9%E6%B3%95">通過繼承來覆寫重載方法</a>

<a href="#%E6%9C%80%E5%B8%B8%E7%94%A8%E7%9A%84%E9%87%8D%E8%BD%BD%E5%9C%BA%E6%99%AF%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95%E7%9A%84%E9%87%8D%E8%BD%BD">最常用的重載場景執行個體方法的重載</a>

<a href="#%E4%BB%8E%E6%A0%87%E5%87%86%E7%B1%BB%E4%B8%AD%E6%B4%BE%E7%94%9F%E7%B1%BB%E6%96%B9%E6%B3%95%E7%9A%84%E9%87%8D%E8%BD%BD">從标準類中派生類方法的重載</a>

我們定義一個類是希望能夠把類當成子產品來使用,并把類嵌入到我們的應用代碼中,與其他的資料類型、邏輯執行流結合使用。一般來說我們可以使用兩種方法在代碼中利用類,那就是組合和派生。

組合: 就是将不同的類混合并加入到其他類中,來 增加類的功能 / 提高代碼的重用性 / 易于維護(對類的修改會直接反應到整個應用中) 。我們可以執行個體化一個更大的對象,同時還可以添加一些執行個體屬性和執行個體方法的實作來豐富執行個體對象的功能。

上述的 class NewAddrBookEntry 有它自身和其他類 Name/Phone 組合而成, 可以實作一些更為複雜的功能。

當我們希望較小的類是較大的類的元件時,組合是一個很好的處理方式。但當我們希望 相同的類卻具有一些不同的功能時 派生就是最好的處理方式。這也是面向對象程式設計最強大的功能之一 —— 使用一個已經定義好的類,擴充它的功能或者對其進行修改生成一個新的類,但卻不會對原來的類造成影響。

子類會從基類繼承他們的任何屬性(資料和方法),這種派生是可以繼承多代的,且可以同時繼承多個基類。

文法:

EXAMPLE:

類 Child 的執行個體對象 c 并沒有定義 <code>__init__()</code> 構造器,但仍然執行了 print 語句,這是因為 Child 從 Parent 繼承了其構造器。

當我們派生一個子類,但同時希望相同的方法能在子類實作不同的功能,這時我們需要使用方法的 重載。使子類的方法能夠覆寫父類的同名方法。

這裡子類 Child 重載了父類 Parent 的 func() 方法,實作了不同的功能。

但仍然有些場合需要我們即能使用子類的重載方法的同時,也要求我們重制父類方法的功能。那麼我們可以調用那個被我們覆寫的父類方法嗎?

答案是肯定的。

我們可以通過 <code>ParentClassName.functionName(object)</code> 的方式來重制父類所被覆寫的方法。當然我們還有其他的方式可以實作這個效果,EG. 在子類的重載方法裡顯式的調用父類的同名方法:

兩種方式本質上是相同的,都是通過 父類名結合句點表達式 來實作對父類方法的調用,而且需要注意的是,在調用的時候必須傳遞一個執行個體對象給 func(),否則會觸發參數不比對的文法錯誤。

還有一個更好的實作方式就是子類使用 super() 内置函數:

super() 内置函數不僅能自動的找到父類方法,并且還是自動的為父類方法傳入 self 參數來實作執行個體方法的綁定。

最常用的重載場景莫過于 重載父類的構造器 了。

在上述的例子可以看出,當我們在子類中沒有重載構造器的時候,會自動的調用父類的構造器。這很明顯是不符合我們的需求的,因為我們常常需要在子類中定義一些新的成員屬性。但是問題是:當我們為了初始化子類中新的成員屬性時,不可避免的需要重複的編寫初始化從父類中繼承而來的屬性的代碼。 這也不符合代碼重用的原則,是以我們一般會采用 重載構造器(init()) + 重制父類構造器(super()) 的方式來解決這個問題。

一般而言,我們會在子類的構造器中首先調用父類的構造器,當然這并不是強制的。隻是為了我們能夠在執行子類構造器的代碼之前首先完成對父類屬性的初始化,防止在調用從父類繼承而來的屬性時仍未初始化的問題出現。

使用 super() 内置函數的漂亮之處在于,我們不需要明确的給出父類的名字,交由解析器去自動的找到該子類的父類,并自動的傳入 self 參數來完成綁定。這樣能夠讓代碼具有更高的靈活性,我們隻需要改變子類的定義語句,就可以改變類的繼承關系。

不可變資料類型的派生:定義一個精度為 2 的浮點資料類型

派生不可變标準類,經常需要重載類方法,而類方法的重載一般是重載 <code>__new__()</code>,也就是所謂的 真·構造器 。

真·構造器會自動的将類對象 RoundFloat 傳入 cls 參數,類似于構造器<code>__init__(self)</code>。

可變資料類型的派生:定義一個有序的字典資料類型

可變資料類型的派生可能不需要使用 構造器 或者 真·構造器 也能夠實作。

通過 SortedDict 生成的字典按照字母的順序排序。

需要注意的是: 在 Python 2.2 之後将類和類型合并了,是以所有的資料類型都是一個類,反之我們定義了一個類也相當于定義了一個新的類型。