Python —物件導向程式設計(Object-Oriented Programming, OOP)基礎教學

Hunter Cheng
學習漂流瓶 Drift Bottle
7 min readNov 21, 2021

物件導向的三大重點為封裝(Encapsulation)、繼承(Inheritance)、多型(Polymorphism),透過這三種方法,可使在寫程式時將內容模擬成現實的情況,換言之就是將其內容實體化,使之更容易理解。

Photo by Safar Safarov on Unsplash

本文介紹會先介紹為何要使用OOP架構,其次是類別 (Class)物件 (Object) 的基礎認識,最後才會進入到OOP三大架構的教學範例,依次為封裝 (Encapsulation)繼承(Inheritance)多型(Polymorphism)。

以下正文開始~

為何要使用OOP架構?

何為POP?何為OOP?兩者差異在哪裡?我現在該使用OOP嗎?

以一開始學習程式的菜鳥來說,普遍都是一條一條的寫程式,加上簡約的 function,並以排序的方式讓程式知道 code 的先後順序,這就是寫程式一般常見的架構 — 程序導向設計 (Procedure-Oriented Programming, POP);而將物件 (Object) 當成基本元件,並封裝進類別 (Class) ,以此為主架構的就是物件導向設計 (Object-Oriented Programming, OOP)

以新手來說,根本不需要學OOP,甚至連 function 都不用寫,以POP的架構就可以一步一步完成作業了。

但是每樣功能存在一定都有它的道理,OOP就是軟體不停開發、演進下的一個產物,當程式能力到一定的程度後,一旦開始做比較大的專案或是計畫,則就會需要用到OOP的技巧。

OOP主是將物件作為程式的基本單元,並將程式函數等封裝於物件中,此封裝後的物件便可當作類別的範例、方法、功能等。由此可知OOP的主要目的就是將程式內容化繁為簡,以一套明確的邏輯架構進行設計,以便加快專案的開發進度,使日後在修改、引用與使用時更為容易。

說實話,在寫這一篇文時,我也很猶豫到底要不要將它完成,畢竟網路上一搜就會有很多OOP、OOD相關的教學文章跳出來;但後來想想,若是以非本科學生的心態下去分享,相較網上其他文章也許會有很大的差異吧,對於那些想跨領域學習程式的學生也許會起到很大的幫助吧!(應該)

什麼是類別(Class)?什麼是物件(Object)?

在進入到封裝、繼承、多型的教學之前,還必須先了解什麼是類別 (Class) 跟物件 (Object) 。

若是上網搜尋類別(Class)和物件(Object)的關係時,普遍跳出的都會是以水果、汽車等…的舉例,沒錯!其實概念都一樣,類別(Class)就像是一概念圖、設計圖、產品的總架構等等,其包含屬性、方法等在產生物件(Object)時需要的所有要素。其對應的相關表如下:

透過上表可知類別(Class)與物件(Object)的關係對應可以是實體也可以是抽象的,只要有一架構,都可以把想呈現的東西以程式表達出來。本文於接下來的實作會以上表第三個類別 Semester 為範例進行演示。

若是想更清楚了解這兩者之間的關係,建議各位可以點下面的影片看 CS Dojo 大大的教學影片,他在敘述類別為 Robot 時非常完整:

封裝 (Encapsulation)繼承(Inheritance)多型(Polymorphism)教學演示

封裝 (Encapsulation)

首先看到封裝的部分,封裝的目的在於讓程式碼更於理解,主要就是將方法(Method)、屬性(Attribute)、建構式(Constructor)封入類別的一個動作。

Semester 類別作為範例:

可看到上述類別 Semester 將屬性(Attribute)為 name、required、elective包在 __init__ 中,且方法(Method), Schedule 和 Credits 也一併包裝進去;之後便可建立 Object 為 Hunter 的課表和學分數;簡單來說,建構完該 Class 後只需輸入該學期對應之個別課程數,便會顯示出這學期總共修了多少課及必修課(Required subject)選修課(Elective subject)的學分。

繼承(Inheritance)

接續上述程式範例。繼承主要是讓程式碼可以重複被使用,借此可以減少浪費在重複性工作的時間。

舉例來說,上述程式只有提及必修課(Required subject)選修課(Elective subject),卻沒有考慮到通識課(General course);那就可以假定上述範例提及的類別 Semester 是 First Semester,通常在 First Semester 是不會有通識課可以選的,會到 Second Semester 才開始可以選。

那在這部分示範就簡單了,將上述 Semester 當作父類,並加入子類 Semester2,當作 Second Semester 的類別,其中必須加入考量 General course 的建構式及方法,子類必須繼承父類,才可在計算課程數與學分時更方便些。

加入子類 Semester2 範例如下:

可看到範例中子類 Semester2 繼承了父類 Semester 的功能。在不考慮 General courses 的情況下,Object 在輸出父類 Schedule 的方法時,只會顯示父類 Required subject 和 Elective subject 的總課程數。

當子類需要繼承父類的 Attribute 時,需加上 super().__init__(),並於第二個括號中填入欲繼承的屬性。範例中 Semester2 直接繼承了 Semester 的全部屬性,並且再加上 Semester2 需求的屬性,general。故於建立 Object 時,若需呼叫子類則必須填上4個變數,而非原本父類的3個。

若子類和父類擁有相同名稱的函示,如範例中的 Credits ,則子類函示會將父類函示給覆蓋掉,優先呼叫出子類函示的結果。

多型(Polymorphism)

先有繼承才有多型,繼承算是多型的基礎,主要概念為一子類繼承多個父類的功能,透過多型可使程式易於維護,是以不會動到既有程式的前提下進行設計的。

以範例應用來看,目前已有 Semester 和 Semester2 兩個類別,假定現在我需要建構一 Credits System (學分計算系統),以便確認在 Required subject、Elective subject 及 General courses 領域到底各修習了多少學分。

加入子類 Credits System 範例如下:

上述範例可看到子類 CreditsSystem 繼承了父類 Semester 和父類 Semester2 ,當 CreditsSystem 輸入對應的4個變數後,代碼會呼叫回原父類中的方法。範例中輸入完變數後,因子類底下 Semester.__init__() Semester2.__init__() 是以呼叫回各自的類別的方式設計,故在最後 Object 的設計時,只需直接呼叫父類的方法,便會完整輸出父類方法的結果。

此學分計算系統藉由輸入 name (人名)、required (必修)、elective (選修)、general (通識) 等資訊,會輸出該學生所有領域的相關學分數。

結語

個人認為透過學習OOP可強化對代碼間關聯性的理解,也可以使 coding 能力突飛猛進,且最快讓新手看不懂你的 code 的方法就是用OOP下去寫,除了防止學弟抄襲你的作業外,也可以達到裝逼的效果~

--

--