第二十六篇:继承与多态——面向对象的核心机制
前言
**继承(Inheritance)和多态(Polymorphism)**是面向对象的两大核心特性,它们让代码更加模块化、可复用且易于扩展。本文将深入讲解 Python 中的单继承、方法重写、super() 的使用,以及多态的实现原理和鸭子类型的实际应用。
什么是继承?
基本语法
class Animal:
"""动物基类"""
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
raise NotImplementedError("子类必须实现此方法")
def info(self):
return f"{self.name}, {self.age}岁"
# 通过 () 指定父类,Dog 继承自 Animal
class Dog(Animal):
def speak(self):
return "汪汪汪!"
# Cat 也继承自 Animal
class Cat(Animal):
def speak(self):
return "喵喵喵~"
# 创建实例
dog = Dog("旺财", 3)
cat = Cat("咪咪", 2)
print(dog.info()) # 旺财,3 岁
print(cat.info()) # 咪咪,2 岁
print(dog.speak()) # 汪汪汪!
print(cat.speak()) # 喵喵喵~
继承的好处:
- 代码复用 —
info()在 Animal 中定义一次,所有子类自动拥有 - 统一接口 — 所有动物都有
speak()方法,可以统一处理 - 易扩展 — 新增动物只需添加新类,无需修改已有代码
super() 函数 —— 调用父类方法
基本用法
class Employee:
"""员工基类"""
def __init__(self, name, salary):
self.name = name
self.salary = salary
def get_details(self):
return f"姓名:{self.name},薪资:¥{self.salary}"
def work(self):
return f"{self.name} 正在工作..."
class Developer(Employee):
"""开发人员"""
def __init__(self, name, salary, programming_language):
# 使用 super() 调用父类构造
super().__init__(name, salary)
self.programming_language = programming_language
def get_details(self):
# 在父类基础上扩展
base_info = super().get_details()
return f"{base_info} | 语言:{self.programming_language}"
def work(self):
return f"{self.name} 正在编写 {self.programming_language} 代码..."
dev = Developer("小明", 20000, "Python")
print(dev.get_details()) # 姓名:小明,薪资:¥20000 | 语言:Python
print(dev.work()) # 小明 正在编写 Python 代码...
super() 的执行顺序
class A:
def __init__(self):
print("A.__init__ 被调用")
class B(A):
def __init__(self):
print("B.__init__ 开始")
super().__init__() # 调用 A.__init__
print("B.__init__ 结束")
class C(A):
def __init__(self):
print("C.__init__ 被调用")
class D(B, C): # 多重继承
def __init__(self):
print("D.__init__ 开始")
super().__init__() # 按 MRO 顺序调用
print("D.__init__ 结束")
d = D()
输出:
D.__init__ 开始
B.__init__ 开始
A.__init__ 被调用
B.__init__ 结束
C.__init__ 被调用
D.__init__ 结束
注意:A.__init__ 只被调用了一次(MRO 保证)。
方法重写
覆盖父类方法
class Shape:
"""图形基类"""
def area(self):
raise NotImplementedError("必须在子类中实现")
def describe(self):
return "一个几何图形"
class Circle(Shape):
"""圆形"""
def __init__(self, radius):
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
def describe(self):
return f"圆,半径={self.radius}"
class Rectangle(Shape):
"""矩形"""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def describe(self):
return f"矩形,宽={self.width},高={self.height}"
# 多态:同一个方法名,不同行为
shapes = [Circle(5), Rectangle(4, 6)]
for shape in shapes:
print(f"{shape.describe()},面积={shape.area():.2f}")
输出:
圆,半径=5,面积=78.54
矩形,宽=4,高=6,面积=24.00
多态与鸭子类型
多态的本质
多态 = 不同对象对同一消息做出不同响应。Python 不要求显式声明接口,而是依赖鸭子类型:
# 鸭子类型:如果它走起来像鸭子,叫起来也像鸭子,那它就是鸭子
def make_it_speak(animal):
animal.speak() # 只要对象有 speak() 方法就可以
class Duck:
def speak(self):
return "嘎嘎嘎!"
class Person:
def speak(self):
return "你好!"
make_it_speak(Duck()) # 嘎嘎嘎!
make_it_speak(Person()) # 你好!
isinstance() 与 issubclass()
虽然鸭子类型推崇动态性,但有时我们仍需要类型检查:
class Animal: pass
class Dog(Animal): pass
class Cat(Animal): pass
dog = Dog()
# isinstance(obj, cls) — 检查对象是否为某个类的实例
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True — 子类的实例也是父类的实例
# issubclass(cls1, cls2) — 检查类是否继承自另一个类
print(issubclass(Dog, Animal)) # True
print(issubclass(Animal, Dog)) # False
# 内置类型检查
print(isinstance([1,2], list)) # True
print(isinstance({"a":1}, dict)) # True
ABC — 抽象基类
当我们需要强制子类实现某些方法时,使用 ABC:
from abc import ABC, abstractmethod
class Printable(ABC):
"""可打印协议"""
@abstractmethod
def print_content(self):
pass
class Document(Printable):
def __init__(self, content):
self.content = content
def print_content(self):
print(f"[文档] {self.content}")
# 如果忘记实现 print_content,会报错
# class BrokenDoc(Printable): # 无 print_content
# pass
doc = Document("Hello World!")
doc.print_content() # [文档] Hello World!
多重继承
基本用法
Python 支持一个类继承多个父类:
class Flyable:
"""飞行能力"""
def fly(self):
return f"{self.name} 正在飞翔..."
class Swimmable:
"""游泳能力"""
def swim(self):
return f"{self.name} 正在游泳..."
class Animal:
def __init__(self, name):
self.name = name
# 鸭子既有飞行能力又有游泳能力,还继承了 Animal
class Duck(Flyable, Swimmable, Animal):
def __init__(self, name):
Animal.__init__(self, name) # 手动调用需要的父类构造函数
def quack(self):
return "嘎嘎嘎!"
duck = Duck("唐老鸭")
print(duck.quack()) # 嘎嘎嘎!
print(duck.fly()) # 唐老鸭 正在飞翔...
print(duck.swim()) # 唐老鸭 正在游泳...
MRO — 方法解析顺序
当一个类继承多个父类且有共同祖先时,Python 按照 MRO(Method Resolution Order) 查找方法:
class A:
def method(self):
return "A.method()"
class B(A):
def method(self):
return "B.method()"
class C(A):
def method(self):
return "C.method()"
class D(B, C):
pass
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]
d = D()
print(d.method()) # B.method() — 优先 B,然后 C,最后 A
查看 MRO 的方法:
# 方法一:mro() 类方法
print(D.mro())
# 方法二:__mro__ 属性
print(D.__mro__)
# 方法三:help() 也会显示 MRO
help(D)
钻石继承问题
class A:
def greet(self):
print("A")
class B(A):
def greet(self):
print("B")
super().greet()
class C(A):
def greet(self):
print("C")
super().greet()
class D(B, C):
def greet(self):
print("D")
super().greet()
d = D()
d.greet()
# 输出:D → B → C → A (A 只执行一次!)
实战示例
示例一:简单的游戏角色系统
class Character:
"""角色基类"""
def __init__(self, name, hp, attack_power):
self.name = name
self.max_hp = hp
self.hp = hp
self.attack_power = attack_power
def is_alive(self):
return self.hp > 0
def take_damage(self, damage):
self.hp = max(0, self.hp - damage)
if not self.is_alive():
print(f"{self.name} 被击败了!")
def attack(self, target):
print(f"{self.name} 攻击 {target.name},造成 {self.attack_power} 点伤害")
target.take_damage(self.attack_power)
class Warrior(Character):
"""战士 — 高攻击力"""
def special_attack(self, target):
critical_damage = self.attack_power * 2
print(f"{self.name} 发动猛击,对 {target.name} 造成 {critical_damage} 点暴击伤害!")
target.take_damage(critical_damage)
class Mage(Character):
"""法师 — 范围攻击"""
def magic_attack(self, targets):
total_damage = self.attack_power * len(targets)
print(f"{self.name} 释放魔法,对所有目标造成 {total_damage} 点总伤害")
for target in targets:
if target.is_alive():
target.take_damage(self.attack_power)
class Healer(Mage):
"""治疗师 — 恢复队友生命"""
def heal(self, target, amount):
healed = min(amount, target.max_hp - target.hp)
target.hp += healed
print(f"{self.name} 治愈 {target.name},恢复 {healed} 点生命")
# 战斗模拟
hero = Warrior("亚瑟", 100, 25)
enemy = Mage("莫甘娜", 80, 20)
healer = Healer("露娜", 70, 15)
print("=== 回合 1 ===")
hero.attack(enemy)
print(f"{enemy.name} 剩余生命值:{enemy.hp}\n")
print("=== 回合 2 ===")
enemy.magic_attack([hero, healer])
print(f"{hero.name} 剩余生命值:{hero.hp}")
print(f"{healer.name} 剩余生命值:{healer.hp}\n")
print("=== 回合 3 ===")
healer.heal(hero, 50)
print(f"{hero.name} 恢复后生命值:{hero.hp}")
示例二:插件系统设计
from abc import ABC, abstractmethod
from typing import List
class Plugin(ABC):
"""插件基类"""
@abstractmethod
def execute(self, data: dict) -> dict:
pass
def name(self) -> str:
return self.__class__.__name__
class DataCleanerPlugin(Plugin):
def execute(self, data):
cleaned = {}
for key, value in data.items():
if isinstance(value, str):
cleaned[key] = value.strip().lower()
else:
cleaned[key] = value
return cleaned
class DataValidatorPlugin(Plugin):
def execute(self, data):
errors = []
if not data.get("email"):
errors.append("缺少邮箱地址")
if "password" in data and len(data["password"]) < 6:
errors.append("密码长度不足")
result = dict(data)
result["errors"] = errors
return result
class FormaterPlugin(Plugin):
def execute(self, data):
formatted = {}
if "birthday" in data:
year, month, day = map(int, data["birthday"].split("-"))
formatted["birth_year"] = year
else:
formatted["birth_year"] = None
formatted.update(data)
return formatted
class PluginManager:
"""插件管理器"""
def __init__(self):
self.plugins: List[Plugin] = []
def register(self, plugin: Plugin):
self.plugins.append(plugin)
print(f"注册插件:{plugin.name()}")
def process(self, data):
for plugin in self.plugins:
data = plugin.execute(data)
return data
# 使用
manager = PluginManager()
manager.register(DataCleanerPlugin())
manager.register(DataValidatorPlugin())
manager.register(FormaterPlugin())
user_data = {"name": "小明 ", "email": "", "password": "123"}
result = manager.process(user_data)
print(result)
# {'name': '小明', 'email': '', 'password': '123',
# 'errors': ['缺少邮箱地址', '密码长度不足'],
# 'birth_year': None}
最佳实践
什么时候该用继承?
# ✅ 适合用继承的场景:
# 1. "是一个"关系明确时
# Dog IS-A Animal → 继承
# ❌ 不适合用继承的场景:
# 1. "有一个"关系 → 考虑组合
# Car HAS-A Engine → 组合更好
# 正确做法:组合替代过度继承
class Engine:
def start(self):
return "引擎启动"
class Car:
def __init__(self):
self.engine = Engine() # 组合,而非继承
def start(self):
return self.engine.start()
避免深层继承树
# ❌ 不好的设计:过深的继承链
class Animal → Mammal → Dog → GuardDog → MilitaryDog → SpecialForcesDog
# ✅ 更好的设计:使用组合 + 行为接口
class FighterBehavior:
def fight(self):
raise NotImplementedError()
class MilitaryDog:
def __init__(self, fighter_behavior: FighterBehavior):
self._fighter = fighter_behavior
def fight(self):
self._fighter.fight()
总结
本文讲解了继承与多态的核心知识:
- 基本继承 — 子类自动获得父类的属性和方法
- super() — 调用父类方法和构造函数,配合 MRO 正确使用
- 方法重写 — 子类覆盖父类方法实现定制行为
- 多态与鸭子类型 — 不同对象响应同一消息
- isinstance/issubclass — 类型检查工具
- ABC 抽象基类 — 强制实现接口契约
- 多重继承与 MRO — 钻石继承问题的解决方案
- 实战应用 — 游戏角色系统、插件系统设计
- 最佳实践 — 组合优于继承、避免深继承树
下一篇文章将深入讲解访问限制:私有属性与封装。
本文是 Python 教程系列的第二十六篇。
