Python 定义一个子类继承父类,并在子类中重写一个方法
核心概念
继承是面向对象编程的核心特性之一,允许子类直接复用父类的属性和方法。方法重写(Override)指子类定义与父类同名的方法,实现对父类行为的定制。这在需要扩展类功能或调整已有逻辑时非常有用。例如,动物类定义基础行为,子类狗/猫/鸟可以重写发声方法。
基础语法
类继承定义
class Animal:
def speak(self):
print("动物发出声音") # 父类基础实现
class Dog(Animal): # 继承Animal类
def speak(self): # 重写speak方法
print("汪汪汪") # 子类定制行为
super()函数调用
class Cat(Animal):
def speak(self):
super().speak() # 调用父类方法
print("喵喵喵") # 补充子类逻辑
多继承示例
class A:
def show(self):
print("A类方法")
class B:
def show(self):
print("B类方法")
class C(A, B): # 多继承
def show(self):
print("C类方法") # 优先使用自己的方法
进阶特性
| 特性 | 说明 | 示例代码 |
|---|---|---|
| 方法绑定 | 子类方法自动绑定实例 | c = C(); c.show() |
| super()链式 | 支持多层继承调用 | super().method() |
| MRO顺序 | 方法解析顺序影响调用路径 | C.__mro__ |
| 抽象方法 | 需强制实现的基类方法 | from abc import ABC, abstractmethod |
完整多继承演示:
class Base:
def action(self):
print("基础操作")
class Extender1(Base):
def action(self):
print("扩展1逻辑")
super().action() # 保持父类调用链
class Extender2(Base):
def action(self):
print("扩展2逻辑")
class Final(Extender1, Extender2): # 继承顺序影响MRO
def action(self):
print("最终实现")
super().action() # 优先调用Extender1
f = Final()
f.action() # 输出顺序体现继承优先级
实战应用
图形面积计算系统
class Shape:
def area(self):
raise NotImplementedError # 强制子类实现
class Rectangle(Shape):
def __init__(self, w, h):
self.width = w # 宽度参数
self.height = h # 高度参数
def area(self):
return self.width * self.height # 重写基础方法
class Circle(Shape):
def __init__(self, r):
self.radius = r # 半径参数
def area(self):
return 3.14159 * self.radius**2 # 重写基础方法
日志系统扩展
class Logger:
def log(self, message):
print(f"[LOG] {message}") # 基础日志记录
class FileLogger(Logger):
def log(self, message):
with open("log.txt", "a") as f: # 打开日志文件
f.write(f"[FILE] {message}\n") # 重写日志方式
注意事项
- 方法签名不一致:子类重写方法参数必须与父类完全匹配,否则会引发
TypeError。例如父类定义def speak(self, volume),子类实现必须包含相同参数。 - 大小写混用:重写方法名需完全匹配大小写,Python区分大小写(如
Speak≠speak)。 - 多重继承优先级:继承顺序决定方法解析优先级,建议通过
ClassName.__mro__查看具体解析顺序。 - super()使用陷阱:在多继承场景中错误使用super()可能导致方法调用遗漏,应结合继承图理解调用链。
高级技巧
动态方法重写
class DynamicOverride:
def greet(self):
print("原始问候")
obj = DynamicOverride()
obj.greet = lambda: print("动态覆盖") # 运行时方法替换
obj.greet() # 执行新绑定的方法
保留父类逻辑的装饰器
def override(parent_method):
def decorator(func):
def wrapper(self, *args, **kwargs):
parent_method(self, *args, **kwargs) # 调用父类方法
return func(self, *args, **kwargs) # 执行子类方法
return wrapper
return decorator
class Parent:
@override(lambda self: print("父类预处理"))
def prepare(self):
print("父类核心处理")
class Child(Parent):
@override(Parent.prepare) # 使用装饰器继承
def prepare(self):
print("子类定制处理")
多继承冲突解决方案
class A:
def show(self):
print("A")
class B:
def show(self):
print("B")
class C(A, B): # 明确继承顺序
def show(self):
A.show(self) # 手动调用指定父类
B.show(self) # 显式调用所有需要的方法
常见问题
Q: 为什么调用super()时会出现无限递归?
A: 子类实现中错误调用了自身方法而非父类方法,例如在Dog类中误写成super().speak()指向了Dog.speak自身。
Q: 如何判断是否需要重写方法?
A: 当子类行为需要与父类完全一致但实现逻辑不同时(如数据结构差异),或需要扩展父类行为时(如增加前置处理),才需要重写。
Q: 多继承中多个父类都有同名方法怎么办?
A: 通过继承顺序控制优先级,或使用显式调用ClassName.method(self)避免super()的自动解析规则。
Q: 重写方法如何访问父类被覆盖的属性?
A: 使用super().__init__()初始化父类属性,或通过super().attribute_name访问父类属性。