方法重写Override是面向对象编程中让子类拥有父类方法独有实现的核心机制,它配合父类引用指向子类对象的用法,能实现运行时多态,让同一段代码在不同对象上表现出不同的行为。理解它的实战用法和运行时表现,是掌握面向对象特性的关键。

方法重写的基础规则
要实现有效的方法重写,需要遵循几个核心规则,否则Override注解会直接报错,或者重写不生效:
- 子类重写的方法访问权限不能比父类被重写方法的访问权限更严格,比如父类方法是public,子类不能是protected或者private
- 子类重写的方法返回值类型必须是父类方法返回值类型的子类或者相同类型,也就是协变返回类型
- 子类重写的方法抛出的异常范围不能比父类被重写方法抛出的异常范围更大
- 被重写的方法不能是private、static、final修饰的,这些修饰符的方法无法被重写
实战:通过Override定制子类行为
我们以一个支付场景为例,父类定义通用的支付流程,不同子类通过重写支付核心方法实现不同的支付逻辑。
定义父类
父类Payment定义了支付的基础流程,其中do_pay方法是核心支付逻辑,留给子类实现:
class Payment:
def __init__(self, amount):
self.amount = amount
# 通用支付流程
def pay(self):
print(f"开始支付,金额:{self.amount}元")
# 调用核心支付方法,由子类重写实现
result = self.do_pay()
if result:
print("支付成功")
else:
print("支付失败")
return result
# 核心支付方法,留给子类重写
def do_pay(self):
raise NotImplementedError("子类必须实现do_pay方法")
定义子类并重写方法
分别定义微信支付和支付宝支付子类,通过Override重写do_pay方法,实现各自的支付逻辑:
class WechatPayment(Payment):
# 重写父类的do_pay方法,实现微信支付逻辑
def do_pay(self):
print("调用微信支付接口")
# 模拟微信支付成功
return True
class AlipayPayment(Payment):
# 重写父类的do_pay方法,实现支付宝支付逻辑
def do_pay(self):
print("调用支付宝支付接口")
# 模拟支付宝支付失败
return False
调用验证子类行为
创建子类实例并调用支付方法,可以看到子类执行的是自己重写的do_pay逻辑:
# 创建微信支付实例
wechat_pay = WechatPayment(100)
wechat_pay.pay()
print("------分割线------")
# 创建支付宝支付实例
alipay_pay = AlipayPayment(200)
alipay_pay.pay()
运行后输出结果如下,可见不同子类的do_pay方法表现完全不同:
开始支付,金额:100元 调用微信支付接口 支付成功 ------分割线------ 开始支付,金额:200元 调用支付宝支付接口 支付失败
运行时多态变量的表现
运行时多态的核心是父类类型的变量,在运行时指向不同的子类对象时,调用重写方法会执行对应子类的方法,而不是父类的方法。我们通过代码来验证这个表现。
多态变量的定义与调用
声明一个Payment类型的变量,分别指向不同的子类实例,调用pay方法观察表现:
# 父类引用指向子类对象,形成多态
payment1 = WechatPayment(150)
payment2 = AlipayPayment(300)
# 调用同一个方法,表现不同
payment1.pay()
print("------分割线------")
payment2.pay()
运行结果和之前直接创建子类实例调用的结果一致,这是因为pay方法内部调用的self.do_pay(),在运行时self的实际类型是子类类型,所以会调用子类重写后的do_pay方法。
多态的底层判断逻辑
Java等静态类型语言中,方法调用在编译期看变量的声明类型,运行期看变量的实际类型,这就是动态绑定。Python作为动态类型语言,变量没有声明类型,调用方法时直接查找对象的实际类型的方法列表,所以重写的方法会直接被调用。我们可以通过type函数查看变量的实际类型:
payment = WechatPayment(100)
print(f"变量的声明类型:{Payment}")
print(f"变量的实际类型:{type(payment)}")
输出结果会显示实际类型是WechatPayment,所以调用do_pay时会找到WechatPayment类中重写的方法。
常见误区与注意事项
- 不要混淆方法重写和方法重载,重写是子类重写父类的同名同参数方法,重载是同一个类中定义同名不同参数的方法,Override注解只用于重写
- 如果父类方法是static修饰的,子类定义同名方法不是重写,而是方法隐藏,不会有多态表现
- 在子类重写方法中,可以通过
super().方法名()调用父类的同名方法,复用父类的逻辑之后再添加子类的独有逻辑
比如修改微信支付子类,先调用父类的校验逻辑再执行支付:
class WechatPayment(Payment):
def do_pay(self):
# 调用父类的校验逻辑(假设父类有校验方法)
# super().validate()
print("调用微信支付接口")
return True
掌握方法重写和运行时多态的表现,能让我们写出更灵活、扩展性更强的代码,后续新增支付方式只需要新增子类重写对应方法即可,不需要修改原有的支付流程代码。