歡迎來到第 3 天!今天我們將探討類別如何在不重複程式碼的情況下共享、擴充並調整行為。

  1. 繼承: 基於既有類別建立新類別,以重複使用程式碼並建立階層結構。
  2. 方法覆寫與 super() 在子類別中重新定義父類別的行為,同時保留對父類別實作的存取。
  3. 多型與鴨子型別: 透過共享介面或共同方法集,對不同物件型別進行操作。

1. 繼承結構 🌳

Python 支援三種主要的繼承類型:

  SINGLE INHERITANCE         MULTILEVEL INHERITANCE        MULTIPLE INHERITANCE

     ┌──────────┐                 ┌──────────┐           ┌───────┐   ┌─────────┐
     │  Parent  │                 │  Grandpa │           │ Mixin │   │ BaseClass│
     └────┬─────┘                 └────┬─────┘           └───┬───┘   └───┬─────┘
          │                            │                     │           │
          ▼                            ▼                     └─────┬─────┘
     ┌──────────┐                 ┌──────────┐                     ▼
     │  Child   │                 │  Parent  │               ┌───────────┐
     └──────────┘                 └────┬─────┘               │   Child   │
                                       │                     └───────────┘
                                       ▼
                                  ┌──────────┐
                                  │  Child   │
                                  └──────────┘

Enter fullscreen mode Exit fullscreen mode

  • 單一繼承: 一個子類別從一個直接父類別繼承。
  • 多層繼承: 子類別繼承自父類別,而父類別本身又繼承自祖父類別(形成鏈狀結構)。
  • 多重繼承: 單一子類別直接從兩個或更多父類別繼承。

2. 方法覆寫與 super() 🔄

  • 方法覆寫: 當子類別定義與父類別方法名稱完全相同的方法時發生。子類別的方法會取代或修改父類別的行為。
  • super() 一個內建函式,允許你在子類別中呼叫父類別的方法。這可以在擴充父類別功能時避免程式碼重複。

🌱 快速範例

class Animal:
    def __init__(self, name: str):
        self.name = name

    def make_sound(self) -> str:
        return "Generic animal sound"

class Dog(Animal):
    def __init__(self, name: str, breed: str):
        # Call parent constructor using super()
        super().__init__(name)
        self.breed = breed

    # Override parent method
    def make_sound(self) -> str:
        parent_sound = super().make_sound()
        return f"{parent_sound} -> Woof! 🐾"

dog = Dog("Rex", "German Shepherd")
print(dog.make_sound())  # Output: Generic animal sound -> Woof! 🐾

Enter fullscreen mode Exit fullscreen mode


3. 多型與鴨子型別 🦆

多型(「多種形狀」)允許不同類別以各自獨特的方式回應相同的方法呼叫。

在 Python 中,多型與 鴨子型別 密切相關:

「如果它走起來像鴨子,叫起來也像鴨子,那它就是一隻鴨子。」

Python 不在乎明確的類別階層或明確的介面合約——只要物件實作了預期的方法(例如 .calculate_pay()),Python 就會愉快地執行它。

                     ┌───────────────────────────────┐
                     │   Payroll Processor Service   │
                     └───────────────┬───────────────┘
                                     │
                      Calls .calculate_pay() on each
                                     │
      ┌──────────────────────────────┼──────────────────────────────┐
      ▼                              ▼                              ▼
┌──────────┐                   ┌──────────┐                   ┌──────────┐
│ FullTime │                   │ Executive│                   │Contractor│
│ Employee │                   │ Manager  │                   │ (No Base)│
└──────────┘                   └──────────┘                   └──────────┘

Enter fullscreen mode Exit fullscreen mode


4. 實作挑戰:建立員工管理系統 🏢

以下是一個企業級的員工管理系統,展示了單一、多層與多重繼承、搭配 super() 的方法覆寫,以及透過統一 PayrollProcessor 實現的鴨子型別。

步驟 1:初始化工作區

uv init oop_day3 && cd oop_day3
touch employee_system.py

Enter fullscreen mode Exit fullscreen mode

步驟 2:實作 employee_system.py

# employee_system.py
from typing import List, Any


# ==========================================
# 1. BASE CLASS (PARENT)
# ==========================================
class Employee:
    """Base class for all salaried employees."""

    def __init__(self, emp_id: str, name: str, base_salary: float):
        self.emp_id = emp_id
        self.name = name
        self.base_salary = base_salary

    def calculate_pay(self) -> float:
        """Calculates standard monthly pay."""
        return round(self.base_salary, 2)

    def get_details(self) -> str:
        return f"[{self.emp_id}] {self.name} | Role: Employee | Base Salary: ${self.base_salary:,.2f}"


# ==========================================
# 2. SINGLE INHERITANCE: DEVELOPER
# ==========================================
class Developer(Employee):
    """Inherits directly from Employee (Single Inheritance)."""

    def __init__(self, emp_id: str, name: str, base_salary: float, tech_stack: str):
        super().__init__(emp_id, name, base_salary)
        self.tech_stack = tech_stack

    # Override calculate_pay to add a tech allowance
    def calculate_pay(self) -> float:
        tech_bonus = 300.00  # Fixed monthly tooling stipend
        return round(super().calculate_pay() + tech_bonus, 2)

    def get_details(self) -> str:
        return f"[{self.emp_id}] {self.name} | Role: Developer ({self.tech_stack})"


# ==========================================
# 3. MULTILEVEL INHERITANCE: MANAGER -> EXECUTIVE
# ==========================================
class Manager(Employee):
    """Inherits from Employee (Level 1)."""

    def __init__(self, emp_id: str, name: str, base_salary: float, team_size: int):
        super().__init__(emp_id, name, base_salary)
        self.team_size = team_size

    def calculate_pay(self) -> float:
        team_allowance = self.team_size * 150.00
        return round(super().calculate_pay() + team_allowance, 2)

    def get_details(self) -> str:
        return f"[{self.emp_id}] {self.name} | Role: Manager | Team Size: {self.team_size}"


class Executive(Manager):
    """Inherits from Manager (Level 2 - Multilevel Inheritance: Employee -> Manager -> Executive)."""

    def __init__(self, emp_id: str, name: str, base_salary: float, team_size: int, stock_options: int):
        super().__init__(emp_id, name, base_salary, team_size)
        self.stock_options = stock_options

    def calculate_pay(self) -> float:
        executive_bonus = 2500.00
        # Combines base salary + team allowance (from Manager) + executive bonus
        return round(super().calculate_pay() + executive_bonus, 2)

    def get_details(self) -> str:
        return f"[{self.emp_id}] {self.name} | Role: Executive | Options: {self.stock_options} units"


# ==========================================
# 4. MULTIPLE INHERITANCE / MIXIN: AUDITABLE
# ==========================================
class ComplianceAuditableMixin:
    """A standalone mixin class that adds auditing capabilities."""

    def log_audit(self, action: str) -> None:
        print(f"[AUDIT LOG] Entity Action Recorded: '{action}'")


class TechLead(Developer, ComplianceAuditableMixin):
    """Inherits from Developer AND ComplianceAuditableMixin (Multiple Inheritance)."""

    def __init__(self, emp_id: str, name: str, base_salary: float, tech_stack: str, projects_count: int):
        Developer.__init__(self, emp_id, name, base_salary, tech_stack)
        self.projects_count = projects_count

    def get_details(self) -> str:
        return f"[{self.emp_id}] {self.name} | Role: Tech Lead | Projects: {self.projects_count}"


# ==========================================
# 5. DUCK TYPING: CONTRACTOR (NO BASE CLASS)
# ==========================================
class ExternalContractor:
    """Does NOT inherit from Employee, but implements calculate_pay() and get_details()."""

    def __init__(self, contractor_id: str, name: str, hourly_rate: float, hours_worked: float):
        self.contractor_id = contractor_id
        self.name = name
        self.hourly_rate = hourly_rate
        self.hours_worked = hours_worked

    def calculate_pay(self) -> float:
        return round(self.hourly_rate * self.hours_worked, 2)

    def get_details(self) -> str:
        return f"[{self.contractor_id}] {self.name} | External Contractor ({self.hours_worked} hrs @ ${self.hourly_rate}/hr)"


# ==========================================
# 6. UNIFIED PAYROLL PROCESSOR (POLYMORPHISM)
# ==========================================
class PayrollProcessor:
    """Uses Polymorphism & Duck Typing to process pay across any compatible worker object."""

    @staticmethod
    def process_payroll(workers: List[Any]) -> None:
        print("==========================================================")
        print("             MONTHLY PAYROLL REPORT                       ")
        print("==========================================================")
        total_payout = 0.0

        for worker in workers:
            # Duck typing in action: as long as worker has get_details() and calculate_pay(), it works
            details = worker.get_details()
            pay = worker.calculate_pay()
            total_payout += pay
            print(f"{details}\n  └─ Calculated Payout: ${pay:,.2f}\n")

        print("----------------------------------------------------------")
        print(f" TOTAL SYSTEM PAYOUT: ${total_payout:,.2f}")
        print("==========================================================\n")


# ==========================================
# TEST EXECUTION SUITE
# ==========================================
if __name__ == "__main__":
    # Create instances across various inheritance patterns
    dev = Developer("EMP-101", "Alice Chen", base_salary=7500.00, tech_stack="Python/FastAPI")
    mgr = Manager("EMP-102", "Bob Smith", base_salary=9000.00, team_size=5)
    exec_officer = Executive("EMP-103", "Carol Danvers", base_salary=15000.00, team_size=20, stock_options=5000)

    # Multiple Inheritance instance
    tech_lead = TechLead("EMP-104", "David Miller", base_salary=11000.00, tech_stack="Distributed Systems", projects_count=3)
    tech_lead.log_audit("Approved Architecture Review")  # Mixin functionality
    # Duck Typing instance (No inheritance from Employee class)
    contractor = ExternalContractor("CONT-801", "Eva Green", hourly_rate=85.00, hours_worked=120)

    # Heterogeneous collection passed into PayrollProcessor
    workforce = [dev, mgr, exec_officer, tech_lead, contractor]

    # Run Polymorphic Payroll
    PayrollProcessor.process_payroll(workforce)

Enter fullscreen mode Exit fullscreen mode

步驟 3:執行並驗證

uv run employee_system.py

Enter fullscreen mode Exit fullscreen mode

輸出摘要

[AUDIT LOG] Entity Action Recorded: 'Approved Architecture Review'

==========================================================
             MONTHLY PAYROLL REPORT                       
==========================================================
[EMP-101] Alice Chen | Role: Developer (Python/FastAPI)
  └─ Calculated Payout: $7,800.00

[EMP-102] Bob Smith | Role: Manager | Team Size: 5
  └─ Calculated Payout: $9,750.00

[EMP-103] Carol Danvers | Role: Executive | Options: 5000 units
  └─ Calculated Payout: $20,500.00

[EMP-104] David Miller | Role: Tech Lead | Projects: 3
  └─ Calculated Payout: $11,300.00

[CONT-801] Eva Green | External Contractor (120 hrs @ $85.0/hr)
  └─ Calculated Payout: $10,200.00

----------------------------------------------------------
 TOTAL SYSTEM PAYOUT: $59,550.00
==========================================================

Enter fullscreen mode Exit fullscreen mode