2025年10月3日 星期五

[水井USR創新教材]Python一下用水井三寶來說明類別的重要概念



本篇文章用「水井三寶」(烏龜、白馬、姻緣花)為主題,展示了 Python 類的七大核心技術:

  • 封裝:保護烏龜的能量值。
  • 繼承:白馬繼承寶物基類的吉祥能力。
  • 多型:烏龜和姻緣花用不同方式「說話」。
  • 類與實例屬性:共享「水井吉祥」,每個寶物有獨特名稱。
  • 特殊方法:姻緣花自訂顯示和加法。
  • 類方法與靜態方法:白馬的召喚和速度計算。
  • 屬性管理:控制烏龜年齡的存取。
以下程式是用Grok產生。

範例一:封裝(Encapsulation)

封裝保護物件內部資料,限制外部直接存取。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Turtle:
    def __init__(self, name):
        self.__energy = 100  # 私有屬性:能量值
        self.name = name

    def get_energy(self):  # 公開方法存取
        return self.__energy

    def use_energy(self, amount):
        if amount > 0:
            self.__energy -= amount
            return f"{self.name} 使用 {amount} 能量,剩餘 {self.__energy}"
        return "無效的能量消耗!"

# 測試
t = Turtle("烏龜")
print(t.get_energy())  # 輸出: 100
print(t.use_energy(20))  # 輸出: 烏龜 使用 20 能量,剩餘 80
# print(t.__energy)  # 錯誤!無法直接存取私有屬性

執行結果:

100 烏龜 使用 20 能量,剩餘 80

解釋:__energy 是私有屬性,外部無法直接存取,只能透過 get_energy 和 use_energy 方法控制,展現封裝保護資料的能力。

範例二:繼承(Inheritance)

繼承讓子類重用父類的屬性和方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Treasure:
    def __init__(self, name):
        self.name = name

    def bless(self):
        return f"{self.name} 帶來吉祥!"

class WhiteHorse(Treasure):  # 繼承 Treasure
    def gallop(self):  # 子類專屬方法
        return f"{self.name} 飛馳千里!"

# 測試
horse = WhiteHorse("白馬")
print(horse.bless())  # 輸出: 白馬 帶來吉祥!(來自父類)
print(horse.gallop())  # 輸出: 白馬 飛馳千里!(子類專有)

執行結果:
白馬 帶來吉祥!
白馬 飛馳千里!

解釋:WhiteHorse 繼承 Treasure,可直接使用父類的 bless 方法,並新增自己的 gallop 方法,展示程式碼重用。

範例三:多型(Polymorphism)
多型允許不同類的物件以統一方式處理不同行為。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Treasure:
    def speak(self):
        pass  # 抽象方法,子類需實現

class Turtle(Treasure):
    def speak(self):
        return "烏龜:穩重長壽!"

class MarriageFlower(Treasure):
    def speak(self):
        return "姻緣花:愛情綻放!"

# 測試
treasures = [Turtle(), MarriageFlower()]
for t in treasures:
    print(t.speak())  # 輸出: 烏龜:穩重長壽! 和 姻緣花:愛情綻放!

執行結果:
烏龜:穩重長壽!
姻緣花:愛情綻放!
解釋:Turtle 和 MarriageFlower 都實現了 speak 方法,但行為不同。透過統一的 speak() 呼叫展現多型。

範例四:類與實例屬性(Class and Instance Attributes)

類屬性共享於所有實例,實例屬性獨立於每個物件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Treasure:
    shared_blessing = "水井吉祥"  # 類屬性

    def __init__(self, name):
        self.name = name  # 實例屬性

    def describe(self):
        return f"{self.name} 擁有 {Treasure.shared_blessing}"

# 測試
t1 = Treasure("烏龜")
t2 = Treasure("白馬")
print(t1.describe())  # 輸出: 烏龜 擁有 水井吉祥
print(t2.describe())  # 輸出: 白馬 擁有 水井吉祥
Treasure.shared_blessing = "三寶輝煌"  # 修改類屬性
print(t1.describe())  # 輸出: 烏龜 擁有 三寶輝煌

執行結果:

烏龜 擁有 水井吉祥 白馬 擁有 水井吉祥 烏龜 擁有 三寶輝煌

解釋:shared_blessing 是類屬性,所有實例共享,修改它會影響所有物件;name 是實例屬性,各物件獨立。

範例五:特殊方法(Magic/Dunder Methods)

特殊方法自訂物件行為,如字串表示或運算。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class MarriageFlower:
    def __init__(self, beauty):
        self.beauty = beauty

    def __str__(self):  # 自訂字串表示
        return f"姻緣花 美麗值: {self.beauty}"

    def __add__(self, other):  # 自訂加法
        total_beauty = self.beauty + other.beauty
        return MarriageFlower(total_beauty)

# 測試
f1 = MarriageFlower(10)
f2 = MarriageFlower(20)
print(f1)  # 輸出: 姻緣花 美麗值: 10
combined = f1 + f2
print(combined)  # 輸出: 姻緣花 美麗值: 30

執行結果:

姻緣花 美麗值: 10 姻緣花 美麗值: 30

解釋:__str__ 自訂 print 輸出;__add__ 讓 + 運算符合併兩朵姻緣花的美麗值,展示特殊方法的靈活性。

範例六:類方法與靜態方法(Class Methods and Static Methods)

類方法操作類本身,靜態方法獨立於類和實例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class WhiteHorse:
    @classmethod
    def summon(cls, name):  # 類方法
        return cls()

    @staticmethod
    def calculate_speed(distance, time):  # 靜態方法
        return f"白馬速度:{distance / time} 公里/小時"

    def __init__(self):
        self.name = "白馬"

# 測試
horse = WhiteHorse.summon("白馬")  # 類方法創建實例
print(WhiteHorse.calculate_speed(100, 2))  # 輸出: 白馬速度:50.0 公里/小時

執行結果:
白馬速度:50.0 公里/小時

解釋:@classmethod 的 summon 使用 cls 創建實例;@staticmethod 的 calculate_speed 獨立計算,無需實例。

範例七:屬性管理(Property Decorators)

屬性裝飾器將方法偽裝成屬性,控制存取。


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Turtle:
    def __init__(self, age):
        self._age = age  # 保護屬性

    @property
    def age(self):  # getter
        return self._age

    @age.setter
    def age(self, value):  # setter
        if value < 0:
            raise ValueError("烏龜年齡不能為負!")
        self._age = value

# 測試
t = Turtle(50)
print(t.age)  # 輸出: 50
t.age = 100  # 使用 setter 修改
print(t.age)  # 輸出: 100
# t.age = -10  # 會拋出錯誤

執行結果:

50 100

解釋:@property 讓 _age 像屬性一樣存取;@age.setter 控制賦值,確保年齡不為負數。