Python 繼承 (Inheritance)

繼承讓子類別可以繼承父類別的屬性和方法,實現程式碼重用和擴展。

基本繼承

# 父類別(基類別)
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} makes a sound")

# 子類別(衍生類別)
class Dog(Animal):
    def bark(self):
        print(f"{self.name} says: Woof!")

# 使用
dog = Dog("Buddy")
dog.speak()  # Buddy makes a sound(繼承自 Animal)
dog.bark()   # Buddy says: Woof!(Dog 自己的方法)

方法覆寫 (Override)

子類別可以覆寫父類別的方法:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} makes a sound")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} says: Woof!")

class Cat(Animal):
    def speak(self):
        print(f"{self.name} says: Meow!")

dog = Dog("Buddy")
cat = Cat("Whiskers")

dog.speak()  # Buddy says: Woof!
cat.speak()  # Whiskers says: Meow!

super() 函數

使用 super() 呼叫父類別的方法:

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def info(self):
        return f"{self.name}, {self.age} years old"

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 呼叫父類別的 __init__
        self.breed = breed
    
    def info(self):
        base_info = super().info()  # 呼叫父類別的 info
        return f"{base_info}, breed: {self.breed}"

dog = Dog("Buddy", 3, "Labrador")
print(dog.info())  # Buddy, 3 years old, breed: Labrador

isinstance() 和 issubclass()

class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

# isinstance 檢查物件是否為某類別的實例
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Animal))  # True(Dog 繼承自 Animal)
print(isinstance(dog, object))  # True(所有類別都繼承自 object)

# issubclass 檢查類別是否為另一類別的子類別
print(issubclass(Dog, Animal))  # True
print(issubclass(Dog, object))  # True
print(issubclass(Animal, Dog))  # False

多重繼承

Python 支援多重繼承,一個類別可以繼承多個父類別:

class Flyable:
    def fly(self):
        print("Flying...")

class Swimmable:
    def swim(self):
        print("Swimming...")

class Duck(Flyable, Swimmable):
    def quack(self):
        print("Quack!")

duck = Duck()
duck.fly()   # Flying...
duck.swim()  # Swimming...
duck.quack() # Quack!

方法解析順序 (MRO)

當多個父類別有相同的方法時,Python 使用 MRO 來決定呼叫哪一個:

class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        print("B")

class C(A):
    def method(self):
        print("C")

class D(B, C):
    pass

d = D()
d.method()  # B(根據 MRO)

# 查看 MRO
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

使用 super() 處理多重繼承

class A:
    def __init__(self):
        print("A init")
        super().__init__()

class B(A):
    def __init__(self):
        print("B init")
        super().__init__()

class C(A):
    def __init__(self):
        print("C init")
        super().__init__()

class D(B, C):
    def __init__(self):
        print("D init")
        super().__init__()

d = D()

輸出:

D init
B init
C init
A init

Mixin

Mixin 是一種提供額外功能的類別,通常不獨立使用:

class JsonMixin:
    def to_json(self):
        import json
        return json.dumps(self.__dict__)

class LogMixin:
    def log(self, message):
        print(f"[{self.__class__.__name__}] {message}")

class User(JsonMixin, LogMixin):
    def __init__(self, name, email):
        self.name = name
        self.email = email

user = User("Alice", "alice@example.com")
print(user.to_json())  # {"name": "Alice", "email": "alice@example.com"}
user.log("User created")  # [User] User created

抽象類別

使用 abc 模組建立抽象類別,強制子類別實作特定方法:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

# shape = Shape()  # TypeError: 不能實例化抽象類別

rect = Rectangle(5, 3)
print(rect.area())       # 15
print(rect.perimeter())  # 16

實際範例

from abc import ABC, abstractmethod

class Employee(ABC):
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    
    @abstractmethod
    def calculate_bonus(self):
        pass
    
    def __str__(self):
        return f"{self.name} - ${self.salary}"

class Manager(Employee):
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)
        self.team_size = team_size
    
    def calculate_bonus(self):
        return self.salary * 0.2 + self.team_size * 100

class Developer(Employee):
    def __init__(self, name, salary, programming_languages):
        super().__init__(name, salary)
        self.programming_languages = programming_languages
    
    def calculate_bonus(self):
        return self.salary * 0.1 + len(self.programming_languages) * 50

# 使用
manager = Manager("Alice", 80000, 5)
developer = Developer("Bob", 70000, ["Python", "JavaScript", "Go"])

print(f"{manager.name}'s bonus: ${manager.calculate_bonus()}")
# Alice's bonus: $16500.0

print(f"{developer.name}'s bonus: ${developer.calculate_bonus()}")
# Bob's bonus: $7150.0