第57集:方法重写
学习目标
- 理解方法重写的概念和作用
- 掌握重写父类方法的语法
- 学会使用super()扩展父类方法
- 理解重写与重载的区别
- 掌握抽象方法和接口
- 学会设计良好的重写
一、方法重写概述
1.1 什么是方法重写
方法重写:子类重新定义父类中已有的方法,提供新的实现。
1.2 重写的作用
┌─────────────────────────────────────┐
│ 父类 (Parent) │
│ method(): 父类实现 │
└─────────────────────────────────────┘
↓ 继承
┌─────────────────────────────────────┐
│ 子类 (Child) │
│ method(): 子类新实现 (重写) │
└─────────────────────────────────────┘重写的好处:
- 提供特定于子类的实现
- 实现多态
- 增强灵活性
- 满足特定需求
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 常见错误
- 忘记实现抽象方法:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
# class Circle(Shape):
# pass # 错误:没有实现抽象方法
# circle = Circle() # 报错:TypeError- 重写时改变方法签名:
class Parent:
def method(self, a, b):
return a + b
class Child(Parent):
def method(self, a): # 参数不匹配
return a * 2
# 虽然不会报错,但改变了方法的接口7.2 注意事项
- 重写时保持方法签名一致
- 使用super()扩展父类方法
- 抽象类不能直接实例化
- 子类必须实现抽象方法
- 合理设计抽象接口
八、课后练习
练习题
编程题
- 定义一个
Shape抽象类 - 创建
Circle、Rectangle、Triangle子类 - 重写计算面积和周长的方法
- 定义一个
编程题
- 定义一个
PaymentMethod抽象类 - 创建
CreditCard、PayPal、Cash子类 - 实现各自的支付逻辑
- 定义一个
思考题
- 重写和重载有什么区别?
- 为什么需要抽象方法和抽象类?
- 什么时候应该使用super()?
九、本集总结
核心知识点回顾
- 方法重写:子类重新定义父类方法
- **super()**:调用和扩展父类方法
- 抽象方法:只有声明,子类必须实现
- 抽象类:包含抽象方法的类,不能实例化
- 重写vs重载:Python只支持重写
下集预告
下一集我们将学习多继承,深入了解如何处理多重继承关系。
学习建议: 理解方法重写的思想,合理设计抽象接口。通过实际编程练习,掌握重写的应用场景和技巧。