第57集:方法重写

学习目标

  • 理解方法重写的概念和作用
  • 掌握重写父类方法的语法
  • 学会使用super()扩展父类方法
  • 理解重写与重载的区别
  • 掌握抽象方法和接口
  • 学会设计良好的重写

一、方法重写概述

1.1 什么是方法重写

方法重写:子类重新定义父类中已有的方法,提供新的实现。

1.2 重写的作用

┌─────────────────────────────────────┐
│          父类 (Parent)              │
│  method(): 父类实现                  │
└─────────────────────────────────────┘
              ↓ 继承
┌─────────────────────────────────────┐
│          子类 (Child)               │
│  method(): 子类新实现 (重写)          │
└─────────────────────────────────────┘

重写的好处:

  1. 提供特定于子类的实现
  2. 实现多态
  3. 增强灵活性
  4. 满足特定需求

1.3 基本示例

class Animal:
    def make_sound(self):
        print("动物发出声音")

class Dog(Animal):
    def make_sound(self):
        print("汪汪汪")  # 重写父类方法

class Cat(Animal):
    def make_sound(self):
        print("喵喵喵")  # 重写父类方法

dog = Dog()
dog.make_sound()  # 输出:汪汪汪

cat = Cat()
cat.make_sound()  # 输出:喵喵喵

二、重写的基本语法

2.1 简单重写

class Parent:
    def greet(self):
        print("父类的问候")

class Child(Parent):
    def greet(self):
        print("子类的问候")  # 完全重写

c = Child()
c.greet()  # 输出:子类的问候

2.2 带参数的重写

class Parent:
    def calculate(self, a, b):
        return a + b

class Child(Parent):
    def calculate(self, a, b):
        return a * b  # 重写,改变计算方式

p = Parent()
c = Child()

print(p.calculate(3, 4))  # 输出:7
print(c.calculate(3, 4))  # 输出:12

三、使用super()扩展父类方法

3.1 为什么要使用super()

class Parent:
    def method(self):
        print("父类方法:第一部分")
        print("父类方法:第二部分")

class Child(Parent):
    def method(self):
        print("子类方法:添加前缀")
        super().method()  # 调用父类方法
        print("子类方法:添加后缀")

c = Child()
c.method()
# 输出:
# 子类方法:添加前缀
# 父类方法:第一部分
# 父类方法:第二部分
# 子类方法:添加后缀

3.2 实际应用示例

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.balance = balance
    
    def deposit(self, amount):
        """存款"""
        if amount > 0:
            self.balance += amount
            print(f"存款{amount}元成功,余额:{self.balance}")

class SavingsAccount(BankAccount):
    def __init__(self, owner, balance, interest_rate):
        super().__init__(owner, balance)
        self.interest_rate = interest_rate
    
    def deposit(self, amount):
        """存款并计算利息"""
        super().deposit(amount)
        interest = amount * self.interest_rate
        self.balance += interest
        print(f"获得利息{interest}元,余额:{self.balance}")

account = SavingsAccount("张三", 1000, 0.05)
account.deposit(500)
# 输出:
# 存款500元成功,余额:1500
# 获得利息25.0元,余额:1525.0

四、重写与重载的区别

4.1 对比表

特性 重写(Override) 重载(Overload)
定义 子类重新定义父类方法 同一类中定义同名不同参数的方法
参数 必须相同 必须不同
返回类型 可以相同或兼容 可以不同
作用域 父子类之间 同一个类中
Python支持 支持 不支持

4.2 Python中的"重载"

Python不支持真正的重载,但可以通过默认参数或可变参数实现类似功能:

class Calculator:
    def add(self, a, b=None, c=None):
        if b is None:
            return a
        elif c is None:
            return a + b
        else:
            return a + b + c

calc = Calculator()
print(calc.add(1))      # 输出:1
print(calc.add(1, 2))   # 输出:3
print(calc.add(1, 2, 3)) # 输出:6

五、抽象方法和接口

5.1 抽象方法

抽象方法:只有方法声明,没有方法实现,子类必须实现。

from abc import ABC, abstractmethod

class Shape(ABC):
    """抽象类"""
    
    @abstractmethod
    def area(self):
        """抽象方法:计算面积"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """抽象方法:计算周长"""
        pass

# 不能直接实例化抽象类
# shape = Shape()  # 报错:TypeError

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

circle = Circle(5)
print(f"面积: {circle.area():.2f}")
print(f"周长: {circle.perimeter():.2f}")

5.2 抽象类

from abc import ABC, abstractmethod

class Vehicle(ABC):
    """交通工具抽象类"""
    
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color
    
    def start(self):
        """公共方法"""
        print(f"{self.brand}汽车启动")
    
    @abstractmethod
    def max_speed(self):
        """抽象方法:子类必须实现"""
        pass

class Car(Vehicle):
    def max_speed(self):
        return 200

class Motorcycle(Vehicle):
    def max_speed(self):
        return 150

car = Car("Toyota", "红色")
car.start()
print(f"最高时速: {car.max_speed()} km/h")

motorcycle = Motorcycle("Yamaha", "黑色")
motorcycle.start()
print(f"最高时速: {motorcycle.max_speed()} km/h")

六、完整示例

6.1 支付系统

from abc import ABC, abstractmethod

class PaymentMethod(ABC):
    """支付方式抽象类"""
    
    @abstractmethod
    def pay(self, amount):
        """支付方法"""
        pass
    
    def check_balance(self, amount):
        """检查余额"""
        if amount <= 0:
            raise ValueError("金额必须大于0")
        return True

class CreditCard(PaymentMethod):
    def __init__(self, card_number, limit):
        self.card_number = card_number
        self.limit = limit
        self.used = 0
    
    def pay(self, amount):
        if not self.check_balance(amount):
            return False
        
        if self.used + amount > self.limit:
            print("信用额度不足")
            return False
        
        self.used += amount
        print(f"信用卡支付{amount}元成功")
        return True

class Cash(PaymentMethod):
    def __init__(self, balance):
        self.balance = balance
    
    def pay(self, amount):
        if not self.check_balance(amount):
            return False
        
        if self.balance < amount:
            print("现金不足")
            return False
        
        self.balance -= amount
        print(f"现金支付{amount}元成功")
        return True

class WeChatPay(PaymentMethod):
    def __init__(self, balance):
        self.balance = balance
    
    def pay(self, amount):
        if not self.check_balance(amount):
            return False
        
        if self.balance < amount:
            print("微信余额不足")
            return False
        
        self.balance -= amount
        print(f"微信支付{amount}元成功")
        return True

# 使用
credit_card = CreditCard("1234567890", 10000)
credit_card.pay(500)

cash = Cash(1000)
cash.pay(200)

wechat = WeChatPay(500)
wechat.pay(300)

6.2 员工薪资系统

from abc import ABC, abstractmethod

class Employee(ABC):
    """员工抽象类"""
    
    def __init__(self, name, base_salary):
        self.name = name
        self.base_salary = base_salary
    
    @abstractmethod
    def calculate_salary(self):
        """计算薪资"""
        pass
    
    def __str__(self):
        return f"{self.__class__.__name__}: {self.name}"

class Manager(Employee):
    def __init__(self, name, base_salary, bonus):
        super().__init__(name, base_salary)
        self.bonus = bonus
    
    def calculate_salary(self):
        """经理薪资 = 基础薪资 + 奖金"""
        return self.base_salary + self.bonus

class Developer(Employee):
    def __init__(self, name, base_salary, hours, hourly_rate):
        super().__init__(name, base_salary)
        self.hours = hours
        self.hourly_rate = hourly_rate
    
    def calculate_salary(self):
        """开发人员薪资 = 基础薪资 + 加班费"""
        overtime_pay = (self.hours - 160) * self.hourly_rate if self.hours > 160 else 0
        return self.base_salary + overtime_pay

class Salesperson(Employee):
    def __init__(self, name, base_salary, commission_rate, sales_amount):
        super().__init__(name, base_salary)
        self.commission_rate = commission_rate
        self.sales_amount = sales_amount
    
    def calculate_salary(self):
        """销售人员薪资 = 基础薪资 + 佣金"""
        commission = self.sales_amount * self.commission_rate
        return self.base_salary + commission

# 使用
manager = Manager("张经理", 15000, 5000)
print(manager)
print(f"薪资: ¥{manager.calculate_salary()}")

developer = Developer("李开发", 12000, 180, 100)
print(developer)
print(f"薪资: ¥{developer.calculate_salary()}")

salesperson = Salesperson("王销售", 8000, 0.1, 50000)
print(salesperson)
print(f"薪资: ¥{salesperson.calculate_salary()}")

七、常见错误与注意事项

7.1 常见错误

  1. 忘记实现抽象方法:
from abc import ABC, abstractmethod

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

# class Circle(Shape):
#     pass  # 错误:没有实现抽象方法

# circle = Circle()  # 报错:TypeError
  1. 重写时改变方法签名:
class Parent:
    def method(self, a, b):
        return a + b

class Child(Parent):
    def method(self, a):  # 参数不匹配
        return a * 2

# 虽然不会报错,但改变了方法的接口

7.2 注意事项

  1. 重写时保持方法签名一致
  2. 使用super()扩展父类方法
  3. 抽象类不能直接实例化
  4. 子类必须实现抽象方法
  5. 合理设计抽象接口

八、课后练习

练习题

  1. 编程题

    • 定义一个Shape抽象类
    • 创建CircleRectangleTriangle子类
    • 重写计算面积和周长的方法
  2. 编程题

    • 定义一个PaymentMethod抽象类
    • 创建CreditCardPayPalCash子类
    • 实现各自的支付逻辑
  3. 思考题

    • 重写和重载有什么区别?
    • 为什么需要抽象方法和抽象类?
    • 什么时候应该使用super()?

九、本集总结

核心知识点回顾

  1. 方法重写:子类重新定义父类方法
  2. **super()**:调用和扩展父类方法
  3. 抽象方法:只有声明,子类必须实现
  4. 抽象类:包含抽象方法的类,不能实例化
  5. 重写vs重载:Python只支持重写

下集预告

下一集我们将学习多继承,深入了解如何处理多重继承关系。


学习建议: 理解方法重写的思想,合理设计抽象接口。通过实际编程练习,掌握重写的应用场景和技巧。

« 上一篇 继承基础 下一篇 » 多继承