iT邦幫忙

2025 iThome 鐵人賽

DAY 7
0
生成式 AI

一塊一塊拼湊的 AI 樂高世界之旅系列 第 7

Day 7:物件導向 Part 2 (繼承、多型、`super()`、封裝 `@property`、抽象類別)

  • 分享至 

  • xImage
  •  

前言

在昨天,我們已經學會了物件導向的基本概念:類別、物件、屬性、方法,並理解了 self__init__ 的作用。這些基礎讓我們能夠建立「藍圖」並產生對應的物件。

然而,真實的專案通常更複雜:

  • 我們需要讓類別之間產生關係(繼承)。
  • 不同類別可能共用相同的方法名稱,但行為各自不同(多型)。
  • 子類別若要沿用父類別的功能,必須能正確地呼叫父類別(super())。
  • 在操作屬性時,可能需要驗證或限制,這時候就會用到 @property
  • 甚至有些設計需要只定義規格、不定義內容,交由子類別來完成(抽象類別)。

用生活來比喻:

  • 繼承:像家族的傳承,小孩繼承父母的特徵。
  • 多型:同樣是「交通工具」,汽車靠輪子跑、飛機靠翅膀飛,但都能「移動」。
  • super():像是小孩遇到不會的事,先請父母處理,再加上自己的做法。
  • 封裝與驗證:就像銀行帳戶餘額不能被隨便更改,必須透過驗證的程序。
  • 抽象類別:像是「比賽規則」只定義動作名稱(跑、跳),具體要怎麼實作由參賽者決定。

今天重點在於讓程式設計更有彈性、更安全,也能用更貼近現實的方式來建模。學會這些後,你會發現物件導向不只是「整理程式碼」,而是真正能讓程式具有擴充性與可維護性的核心。


繼承與多型

繼承:子類別會繼承父類別屬性與方法。
多型:不同子類別各自覆寫同一個方法,表現出不同行為。

class Father:
    def __init__(self, name):
        self.name = name

    def skill(self):
        return "會開車"

# [子類別] 小孩繼承爸爸
class Son(Father):
    def skill(self):
        return "打電動"

class Daughter(Father):
    def skill(self):
        return "彈鋼琴"

family = [Father("爸爸"), Son("小明"), Daughter("小美")]

for member in family:
    print(f"{member.name}:{member.skill()}")


super() 的用途

子類別要沿用父類別的初始化邏輯時,用 super() 呼叫父類別版本:

class Father:
    def __init__(self, name):
        self.name = name

    def skill(self):
        return "會開車"

class Son(Father):
    def __init__(self, name, hobby):
        super().__init__(name)       # 呼叫父類別 __init__
        self.hobby = hobby

    def skill(self):
        return super().skill() + ",也會打電動"

class Daughter(Father):
    def __init__(self, name, hobby):
        super().__init__(name)
        self.hobby = hobby

    def skill(self):
        return super().skill() + ",也會彈鋼琴"


# 建立物件
dad = Father("爸爸")
son = Son("小明", "打電動")
daughter = Daughter("小美", "彈鋼琴")

print(f"{dad.name}:{dad.skill()}")
print(f"{son.name}:{son.skill()}")
print(f"{daughter.name}:{daughter.skill()}")

封裝與驗證:@property

讓屬性在存取時多一層驗證或計算,外部使用方式仍像操作屬性。

class Student:
    def __init__(self, name, grade):
        self.name = name
        self._grade = None
        self.grade = grade   # setter 驗證

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self, value):
        if not (0 <= value <= 100):
            raise ValueError("成績必須在 0~100")
        self._grade = value
        
# 建立學生物件
s1 = Student("小明", 90)

# 讀取成績(實際上呼叫的是 @property 的 getter)
print(s1.grade)      # 輸出:90

# 修改成績(實際上呼叫的是 setter)
s1.grade = 75
print(s1.grade)      # 輸出:75

# 嘗試給不合法的數值
try:
    s1.grade = 150   # 超過 100,不合法
except ValueError as e:
    print("錯誤:", e)

# 讀取名字(普通屬性,不受影響)
print(s1.name)       # 輸出:小明


常見整理

類型 宣告方式 常見用途
實例方法 def m(self, ...) 操作物件資料
類別方法 @classmethod def m(cls) 類別邏輯、替代建構子
靜態方法 @staticmethod def m() 工具性函數
封裝 getter @property 攔截屬性讀取
封裝 setter @x.setter 寫入驗證

上一篇
# Day 6:物件導向 Part 1 (類別、物件、屬性、方法、self、__init__)
下一篇
Day 8:Async 非同步程式設計
系列文
一塊一塊拼湊的 AI 樂高世界之旅8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言