2026年10月31日 星期六

Python 多型:為什麼相同的方法可以有不同的行為?

Python 多型(Polymorphism):為什麼相同的方法可以有不同的行為?

Python 物件導向程式設計系列(三)|Class × Inheritance × Polymorphism × AI 協作學習

Python 實習物件導向智慧養殖AI 協作

前面我們學過類別(Class)與繼承(Inheritance)。類別幫助我們組織資料與行為;繼承讓不同類別共用既有功能。接下來要學習另一個重要觀念:多型(Polymorphism)。

核心觀念:相同的方法名稱,面對不同物件,可以產生不同的行為。重點不是把程式寫得更花俏,而是讓程式更容易擴充。

一、從生活情境理解多型

如果你對學生與老師都說「請介紹自己」,學生可能說「我正在學 Python」,老師可能說「我教授 Python」。相同的指令,因對象不同而產生不同的回應。

class Student:
    def introduce(self):
        print("我是學生,正在學習 Python")

class Teacher:
    def introduce(self):
        print("我是老師,負責教授 Python")

student = Student()
teacher = Teacher()
student.introduce()
teacher.introduce()
我是學生,正在學習 Python
我是老師,負責教授 Python

兩個類別都具有 introduce() 方法,但實際執行內容不同。這也說明:Python 的多型不一定需要繼承。

二、水井村智慧養殖池:同一個方法,不同行為

假設有三種養殖池:一般養殖池顯示溶氧;智慧養殖池判斷異常;AI 智慧養殖池提供管理建議。它們都可以使用 check_status(),但執行內容不同。

check_status()相同方法呼叫Pond一般養殖池顯示溶氧數值SmartPond智慧養殖池判斷溶氧是否異常AIPondAI 智慧養殖池提供管理建議呼叫方式相同,實際行為由物件決定

三、建立父類別 Pond

class Pond:
    def __init__(self, name, oxygen):
        self.name = name
        self.oxygen = oxygen

    def check_status(self):
        return f"{self.name}:溶氧 {self.oxygen}"

父類別提供所有養殖池共通的資料與方法。

四、使用繼承與方法覆寫實現多型

class SmartPond(Pond):
    def check_status(self):
        if self.oxygen < 5:
            return f"{self.name}:溶氧偏低"
        return f"{self.name}:溶氧正常"

class AIPond(Pond):
    def check_status(self):
        if self.oxygen < 5:
            return f"{self.name}:建議檢查增氧設備"
        return f"{self.name}:目前環境正常"

子類別重新定義父類別原有的 check_status(),稱為方法覆寫(Method Overriding)。注意:此處的 AIPond 只是規則式建議,尚未連接真正的 AI 模型。

五、同一個 for 迴圈管理不同物件

ponds = [
    Pond("一號池", 5.8),
    SmartPond("二號池", 4.2),
    AIPond("三號池", 4.3)
]

for pond in ponds:
    print(pond.check_status())
一號池:溶氧 5.8
二號池:溶氧偏低
三號池:建議檢查增氧設備

這段程式不需要判斷每個物件是哪個類別。Python 會根據物件的實際類型,選擇對應的方法。這種行為也稱為動態派送(Dynamic Dispatch)。

六、新增魚菜共生養殖池,原本迴圈不必修改

class AquaponicsPond(Pond):
    def __init__(self, name, oxygen, water_level):
        super().__init__(name, oxygen)
        self.water_level = water_level

    def check_status(self):
        if self.water_level < 30:
            return f"{self.name}:水位偏低"
        if self.oxygen < 5:
            return f"{self.name}:溶氧偏低"
        return f"{self.name}:系統正常"

ponds.append(AquaponicsPond("四號池", 5.6, 25))

for pond in ponds:
    print(pond.check_status())
一號池:溶氧 5.8
二號池:溶氧偏低
三號池:建議檢查增氧設備
四號池:水位偏低

新增類別後,原本的迴圈仍然可以使用,這是多型對軟體擴充的重要價值。以上警戒值僅供教學,實際系統須依養殖物種與設備設定。

七、多型一定要有繼承嗎?

不一定。Python 有鴨子型別(Duck Typing)的特性:只要物件提供程式需要的方法,就能以相同方式使用。

class Dog:
    def speak(self):
        return "汪汪"

class Cat:
    def speak(self):
        return "喵喵"

animals = [Dog(), Cat()]
for animal in animals:
    print(animal.speak())
汪汪
喵喵

Dog 和 Cat 沒有共同的自訂父類別,卻都能回應 speak()。

八、Class、Inheritance、Polymorphism 比較

觀念核心問題養殖池範例
Class 類別如何組織資料與行為?建立 Pond
Inheritance 繼承如何共用並擴充既有設計?SmartPond(Pond)
Polymorphism 多型如何以相同方式操作不同物件?check_status()

九、AI 時代的多型實習挑戰

No-AI:先預測

不使用 AI,閱讀三種養殖池程式,預測執行結果,並說明為何相同的 check_status() 會有不同輸出。

AI Pair:比較設計

請 AI 寫出兩種版本:一種以 if/elif 判斷類別,一種使用多型。比較新增養殖池時需要修改哪些程式。

Challenge AI:擴充系統

新增 ShrimpPond 類別,提供專屬狀態檢查功能,卻不能修改原本的 for 迴圈。

建議提示詞:

我正在學習 Python 多型。請以智慧養殖系統為例,建立 Pond、SmartPond、AIPond 與 ShrimpPond 類別。每個類別都有 check_status() 方法,但執行不同功能。請展示如何用同一個 for 迴圈操作不同物件,並解釋方法覆寫、動態派送與多型的關係。程式請保持簡單,適合大學生實習。

十、結語:AI 會寫多型,但你知道何時需要嗎?

當系統只有一種養殖池時,可能不需要多型;當系統逐漸擴充,包含不同設備與監控規則時,多型就能讓程式用一致的方式操作不同物件。

最重要的觀念:相同的操作介面,可以對不同物件產生不同的行為。AI 可以幫忙寫程式,但學生仍要能判斷如何設計、何時擴充,以及是否過度設計。

沒有留言:

張貼留言