第5章:继承与多态
📚 学习目标
Specific (具体):
- 深入理解面向对象编程中的继承机制
- 掌握Python类的继承语法和super()函数使用
- 理解多态的概念和实现方式
- 学会 抽象类和接口的设计模式
Measurable (可衡量):
- 能够设计并实现包含3层以上继承关系的类体系
- 正确完成95%以上的继承和多态编程练习
- 独立完成一个复杂的多层继承项目案例
Achievable (可实现):
- 基于第4章面向对象基础,深入学习高级特性
- 通过动物园、GUI框架等经典案例理解继承
Relevant (相关性):
- 为设计模式和框架开发奠定理论基础
- 培养软件架构设计思维
Time-bound (时限性):
- 2周内完成学习(4课时理论+实践)
🗺️ 知识导图
💡 5.1 继承基础概念
5.1.1 什么是继承?
继承是面向对象编程的核心特性之一,它允许我们基于现有的类创建新的类。新类(子类)可以获得现有类(父类)的所有属性和方法,同时还可以添加自己特有的属性和方法。
生活中的继承例子:
- 🧬 生物学继承:孩子继承父母的基 因特征
- 🏰 财产继承:子女继承家族的财产
- 📚 知识传承:学生继承老师的知识体系
编程中的继承:
# 父类(基类)class Animal:def __init__(self, name, age):self.name = nameself.age = agedef eat(self):print(f"{self.name}正在吃东西")def sleep(self):print(f"{self.name}正在睡觉")# 子类(派生类)class Dog(Animal): # Dog继承自Animaldef __init__(self, name, age, breed):super().__init__(name, age) # 调用父类构造函数self.breed = breed # 子类特有属性def bark(self): # 子类特有方法print(f"{self.name}在汪汪叫")def eat(self): # 重写父类方法print(f"小狗{self.name}正在吃狗粮")# 使用继承dog = Dog("旺财", 3, "金毛")dog.eat() # 调用重写的方法dog.sleep() # 调用继承的方法dog.bark() # 调用子类特有方法
5.1.2 继承的好处
1. 代码复用
class Vehicle:"""交通工具基类"""def __init__(self, brand, model, year):self.brand = brandself.model = modelself.year = yearself.speed = 0self.is_running = Falsedef start(self):self.is_running = Trueprint(f"{self.brand} {self.model} 启动了")def stop(self):self.is_running = Falseself.speed = 0print(f"{self.brand} {self.model} 停止了")def accelerate(self, increment):if self.is_running:self.speed += incrementprint(f"当前速度:{self.speed}km/h")class Car(Vehicle):"""汽车类"""def __init__(self, brand, model, year, doors):super().__init__(brand, model, year)self.doors = doorsdef honk(self):print("嘀嘀!")class Motorcycle(Vehicle):"""摩托车类"""def __init__(self, brand, model, year, engine_size):super().__init__(brand, model, year)self.engine_size = engine_sizedef wheelie(self):print("摩托车后轮腾空!")# 所有车辆都可以使用Vehicle的基本功能car = Car("丰田", "卡罗拉", 2023, 4)motorcycle = Motorcycle("雅马哈", "R1", 2023, 1000)car.start()car.accelerate(50)car.honk()motorcycle.start()motorcycle.accelerate(80)motorcycle.wheelie()
2. 层次结构建立
class Employee:"""员工基类"""def __init__(self, emp_id, name, department):self.emp_id = emp_idself.name = nameself.department = departmentself.salary = 0self.projects = []def add_project(self, project):self.projects.append(project)print(f"{self.name}加入项目:{project}")def get_info(self):return f"{self.name} - {self.department}部门"class Developer(Employee):"""开发人员类"""def __init__(self, emp_id, name, department, programming_languages):super().__init__(emp_id, name, department)self.programming_languages = programming_languagesself.salary = 12000def code(self, language):if language in self.programming_languages:print(f"{self.name}正在用{language}编程")else:print(f"{self.name}不熟悉{language}")def debug(self):print(f"{self.name}正在调试代码")class Manager(Employee):"""管理人员类"""def __init__(self, emp_id, name, department, team_size):super().__init__(emp_id, name, department)self.team_size = team_sizeself.salary = 20000self.subordinates = []def hold_meeting(self):print(f"{self.name}召开团队会议")def assign_task(self, developer, task):print(f"{self.name}给{developer.name}分配任务:{task}")class Intern(Developer):"""实习生类"""def __init__(self, emp_id, name, department, programming_languages, university):super().__init__(emp_id, name, department, programming_languages)self.university = universityself.salary = 3000def learn(self, technology):print(f"实习生{self.name}正在学习{technology}")# 创建不同类型的员工dev = Developer("D001", "张三", "技术", ["Python", "JavaScript"])manager = Manager("M001", "李四", "技术", 10)intern = Intern("I001", "王五", "技术", ["Python"], "清华大学")# 所有员工都有基本功能print(dev.get_info())print(manager.get_info())print(intern.get_info())# 各自的特殊功能dev.code("Python")manager.hold_meeting()intern.learn("React")
5.1.3 is-a关系
继承体现的是"is-a"(是一个)关系,这是区分继承和组合的重要标准。
# 正确的继承关系 - is-aclass Shape:def area(self):passclass Circle(Shape): # Circle is a Shape ✓def __init__(self, radius):self.radius = radiusdef area(self):return 3.14159 * self.radius ** 2class Rectangle(Shape): # Rectangle is a Shape ✓def __init__(self, width, height):self.width = widthself.height = heightdef area(self):return self.width * self.height# 错误的继承关系示例class Engine:def start(self):print("引擎启动")# 错误!Car is not an Engine# class Car(Engine): # ❌ 错误:汽车不是引擎# pass# 正确的做法:组合关系 - has-aclass Car:def __init__(self):self.engine = Engine() # Car has an Engine ✓def start(self):self.engine.start()
🔧 5.2 继承语法详解
5.2.1 基本继承语法
class Parent:"""父类"""def __init__(self, name):self.name = nameself.family_trait = "善良"def introduce(self):print(f"我是{self.name},我很{self.family_trait}")class Child(Parent):"""子类继承父类"""def __init__(self, name, age):super().__init__(name) # 调用父类构造函数self.age = agedef introduce(self):super().introduce() # 调用父类方法print(f"我今年{self.age}岁")# 测试继承parent = Parent("王父")child = Child("王子", 25)parent.introduce()print("---")child.introduce()
5.2.2 super()函数详解
super()函数是Python中调用父类方法的标准方式:
class Animal:def __init__(self, name, species):self.name = nameself.species = speciesprint(f"Animal构造函数:创建了{species} {name}")def make_sound(self):print(f"{self.name}发出了声音")def info(self):return f"{self.name}是一只{self.species}"class Dog(Animal):def __init__(self, name, breed):# 调用父类构造函数super().__init__(name, "犬")self.breed = breedprint(f"Dog构造函数:这是一只{breed}")def make_sound(self):# 扩展父类方法super().make_sound() # 先调用父类方法print("汪汪汪!") # 再添加子类特有行为def info(self):# 重写父类方法base_info = super().info()return f"{base_info},品种是{self.breed}"class Puppy(Dog):def __init__(self, name, breed, age_months):super().__init__(name, breed)self.age_months = age_monthsprint(f"Puppy构造函数:{age_months}个月大")def make_sound(self):print(f"小狗{self.name}奶声奶气地叫:")super().make_sound() # 调用Dog的make_sounddef play(self):print(f"{self.age_months}个月大的{self.name}在玩耍")# 测试多层继承中的super()puppy = Puppy("小白", "金毛", 3)print("---")puppy.make_sound()print("---")print(puppy.info())print("---")puppy.play()
5.2.3 方法重写(Override)
子类可以重写父类的方法来实现不同的行为:
class Shape:"""图形基类"""def __init__(self, color):self.color = colordef area(self):"""计算面积 - 在基类中抛出异常,强制子类实现"""raise NotImplementedError("子类必须实现area方法")def perimeter(self):"""计算周长 - 在基类中抛出异常,强制子类实现"""raise NotImplementedError("子类必须实现perimeter方法")def description(self):"""图形描述 - 提供默认实现"""return f"这是一个{self.color}的图形"class Circle(Shape):def __init__(self, color, radius):super().__init__(color)self.radius = radiusdef area(self):"""重写area方法"""import mathreturn math.pi * self.radius ** 2def perimeter(self):"""重写perimeter方法"""import mathreturn 2 * math.pi * self.radiusdef description(self):"""重写description方法"""base_desc = super().description()return f"{base_desc},半径为{self.radius}的圆形"class Rectangle(Shape):def __init__(self, color, width, height):super().__init__(color)self.width = widthself.height = heightdef area(self):"""重写area方法"""return self.width * self.heightdef perimeter(self):"""重写perimeter方法"""return 2 * (self.width + self.height)def description(self):"""重写description方法"""base_desc = super().description()return f"{base_desc},{self.width}x{self.height}的矩形"class Square(Rectangle):def __init__(self, color, side):super().__init__(color, side, side)self.side = sidedef description(self):"""再次重写description方法"""return f"这是一个{self.color}的正方形,边长为{self.side}"# 测试方法重写shapes = [Circle("红色", 5),Rectangle("蓝色", 4, 6),Square("绿色", 3)]for shape in shapes:print(shape.description())print(f"面积:{shape.area():.2f}")print(f"周长:{shape.perimeter():.2f}")print("---")
5.2.4 属性继承和访问控制
class BankAccount:"""银行账户基类"""def __init__(self, account_number, holder_name, initial_balance):self.account_number = account_number # 公共属性self.holder_name = holder_name # 公共属性self._balance = initial_balance # 保护属性self.__pin = "1234" # 私有属性self._transaction_history = [] # 保护属性def deposit(self, amount):"""存款 - 公共方法"""if amount > 0:self._balance += amountself._add_transaction(f"存款 +{amount}")print(f"存款成功,余额:{self._balance}")def _add_transaction(self, description):"""添加交易记录 - 保护方法"""from datetime import datetimeself._transaction_history.append({'time': datetime.now(),'description': description})def __validate_pin(self, pin):"""验证PIN码 - 私有方法"""return pin == self.__pindef get_balance(self):"""获取余额 - 公共方法"""return self._balancedef get_transaction_history(self):"""获取交易历史 - 公共方法"""return self._transaction_history.copy()class SavingsAccount(BankAccount):"""储蓄账户"""def __init__(self, account_number, holder_name, initial_balance, interest_rate):super().__init__(account_number, holder_name, initial_balance)self.interest_rate = interest_ratedef add_interest(self):"""添加利息"""interest = self._balance * self.interest_rate # 可以访问保护属性self._balance += interestself._add_transaction(f"利息 +{interest:.2f}") # 可以调用保护方法print(f"利息已添加:{interest:.2f},余额:{self._balance}")def withdraw(self, amount):"""取款 - 储蓄账户有限制"""if amount <= self._balance:self._balance -= amountself._add_transaction(f"取款 -{amount}")print(f"取款成功,余额:{self._balance}")else:print("余额不足")class CheckingAccount(BankAccount):"""支票账户"""def __init__(self, account_number, holder_name, initial_balance, overdraft_limit):super().__init__(account_number, holder_name, initial_balance)self.overdraft_limit = overdraft_limitdef withdraw(self, amount):"""取款 - 支票账户允许透支"""if amount <= self._balance + self.overdraft_limit:self._balance -= amountself._add_transaction(f"取款 -{amount}")print(f"取款成功,余额:{self._balance}")else:print(f"超出透支限额")def get_available_balance(self):"""获取可用余额"""return self._balance + self.overdraft_limit# 测试属性继承和访问控制savings = SavingsAccount("S001", "张三", 10000, 0.03)checking = CheckingAccount("C001", "李四", 5000, 2000)# 测试公共方法和保护属性的访问savings.deposit(1000)savings.add_interest()checking.deposit(500)checking.withdraw(6000) # 使用透支print(f"可用余额:{checking.get_available_balance()}")# 私有属性无法直接访问# print(savings.__pin) # 会报错
继续编写第5章的其他内容...
🎭 5.3 多态机制
5.3.1 多态的概念
多态(Polymorphism)是面向对象编程的重要特性,意思是"一个接口,多种实现"。同一个方法调用可以根据对象的不同而表现出不同的行为。
生活中的多态例子:
- 🎵 乐器演奏:不同乐器都能"播放音乐",但声音不同
- 🚗 交通工具:汽车、自行车、飞机都能"移动",但方式不同
- 🐾 动物叫声:猫咪"喵喵"、狗狗"汪汪"、鸟儿"啾啾"
class Animal:"""动物基类"""def __init__(self, name):self.name = namedef make_sound(self):"""发出声音 - 基类提供默认实现"""print(f"{self.name}发出了声音")def move(self):"""移动方式 - 基类提供默认实现"""print(f"{self.name}在移动")class Dog(Animal):def make_sound(self):print(f"狗狗{self.name}:汪汪汪!")def move(self):print(f"狗狗{self.name}在奔跑")class Cat(Animal):def make_sound(self):print(f"猫咪{self.name}:喵喵喵~")def move(self):print(f"猫咪{self.name}在优雅地走步")class Bird(Animal):def make_sound(self):print(f"鸟儿{self.name}:啾啾啾♪")def move(self):print(f"鸟儿{self.name}在天空中飞翔")class Fish(Animal):def make_sound(self):print(f"鱼儿{self.name}:...(鱼不会叫)")def move(self):print(f"鱼儿{self.name}在水中游泳")# 多态的威力:同一个函数处理不同类型的对象def animal_concert(animals):"""动物音乐会 - 展示多态"""print("🎵 动物音乐会开始了!🎵")for animal in animals:animal.make_sound() # 同一个方法调用,不同的行为print("\n🏃♀️ 动物运动会开始了!🏃♀️")for animal in animals:animal.move() # 同一个方法调用,不同的行为# 创建不同类型的动物zoo_animals = [Dog("旺财"),Cat("咪咪"),Bird("小鸟"),Fish("金鱼")]# 多态:同一个函数,处理不同类型的对象animal_concert(zoo_animals)
5.3.2 方法重写与动态绑定
Python使用动态绑定实现多态,即在运行时决定调用哪个类的方法:
class MediaPlayer:"""媒体播放器基类"""def __init__(self, filename):self.filename = filenameself.is_playing = Falsedef play(self):"""播放媒体"""self.is_playing = Trueprint(f"正在播放:{self.filename}")def stop(self):"""停止播放"""self.is_playing = Falseprint(f"停止播放:{self.filename}")def get_info(self):"""获取媒体信息"""return f"媒体文件:{self.filename}"class AudioPlayer(MediaPlayer):"""音频播放器"""def __init__(self, filename, bitrate):super().__init__(filename)self.bitrate = bitratedef play(self):"""重写播放方法"""print(f"🎵 开始播放音频:{self.filename}")print(f" 音质:{self.bitrate}kbps")self.is_playing = Truedef get_info(self):"""重写信息获取方法"""base_info = super().get_info()return f"{base_info},音质:{self.bitrate}kbps"def adjust_volume(self, level):"""音频特有方法"""print(f"调整音量到:{level}%")class VideoPlayer(MediaPlayer):"""视频播放器"""def __init__(self, filename, resolution):super().__init__(filename)self.resolution = resolutiondef play(self):"""重写播放方法"""print(f"🎬 开始播放视频:{self.filename}")print(f" 分辨率:{self.resolution}")self.is_playing = Truedef get_info(self):"""重写信息获取方法"""base_info = super().get_info()return f"{base_info},分辨率:{self.resolution}"def toggle_fullscreen(self):"""视频特有方法"""print("切换全屏模式")class ImageViewer(MediaPlayer):"""图片查看器"""def __init__(self, filename, dimensions):super().__init__(filename)self.dimensions = dimensionsdef play(self):"""重写播放方法"""print(f"🖼️ 显示图片:{self.filename}")print(f" 尺寸:{self.dimensions}")self.is_playing = Truedef get_info(self):"""重写信息获取方法"""base_info = super().get_info()return f"{base_info},尺寸:{self.dimensions}"def zoom(self, factor):"""图片特有方法"""print(f"缩放图片:{factor}倍")# 多态应用:媒体播放系统class PlaylistManager:"""播放列表管理器"""def __init__(self):self.playlist = []def add_media(self, media):"""添加媒体文件"""self.playlist.append(media)print(f"添加到播放列表:{media.filename}")def play_all(self):"""播放所有媒体 - 展示多态"""print("\n🎪 开始播放播放列表...")for media in self.playlist:print(f"\n📄 {media.get_info()}")media.play() # 多态:不同类型的媒体有不同的播放方式print("---")def get_playlist_info(self):"""获取播放列表信息"""print("\n📋 播放列表信息:")for i, media in enumerate(self.playlist, 1):print(f"{i}. {media.get_info()}")# 创建不同类型的媒体播放器playlist = PlaylistManager()playlist.add_media(AudioPlayer("经典老歌.mp3", 320))playlist.add_media(VideoPlayer("搞笑视频.mp4", "1080p"))playlist.add_media(ImageViewer("美丽风景.jpg", "1920x1080"))# 多态:同一个方法调用,不同的行为playlist.get_playlist_info()playlist.play_all()
5.3.3 抽象基类(ABC)
抽象基类提供了一种定义接口的方式,确保子类必须实现特定的方法:
from abc import ABC, abstractmethodclass Shape(ABC):"""抽象形状类"""def __init__(self, color):self.color = color@abstractmethoddef area(self):"""抽象方法:计算面积"""pass@abstractmethoddef perimeter(self):"""抽象方法:计算周长"""passdef display(self):"""具体方法:显示信息"""print(f"这是一个{self.color}的{self.__class__.__name__}")print(f"面积:{self.area():.2f}")print(f"周长:{self.perimeter():.2f}")class Circle(Shape):"""圆形类"""def __init__(self, color, radius):super().__init__(color)self.radius = radiusdef area(self):"""实现抽象方法"""import mathreturn math.pi * self.radius ** 2def perimeter(self):"""实现抽象方法"""import mathreturn 2 * math.pi * self.radiusclass Rectangle(Shape):"""矩形 类"""def __init__(self, color, width, height):super().__init__(color)self.width = widthself.height = heightdef area(self):"""实现抽象方法"""return self.width * self.heightdef perimeter(self):"""实现抽象方法"""return 2 * (self.width + self.height)class Triangle(Shape):"""三角形类"""def __init__(self, color, a, b, c):super().__init__(color)self.a = a # 边长aself.b = b # 边长bself.c = c # 边长cdef area(self):"""实现抽象方法:使用海伦公式"""s = (self.a + self.b + self.c) / 2 # 半周长import mathreturn math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))def perimeter(self):"""实现抽象方法"""return self.a + self.b + self.c# 抽象基类的应用def calculate_total_area(shapes):"""计算多个形状的总面积 - 展示多态"""total = 0print("📐 形 状信息统计:")for i, shape in enumerate(shapes, 1):print(f"\n{i}. {shape.__class__.__name__}:")shape.display()total += shape.area()print(f"\n📊 总面积:{total:.2f}")return total# 创建不同形状shapes = [Circle("红色", 5),Rectangle("蓝色", 4, 6),Triangle("绿色", 3, 4, 5)]# 多态应用calculate_total_area(shapes)# 尝试创建抽象类实例会报错# shape = Shape("颜色") # TypeError: Can't instantiate abstract class
5.3.4 鸭子类型(Duck Typing)
Python的"鸭子类型":如果它走路像鸭子,叫声像鸭子,那它就是鸭子。
# 鸭子类型示例:文件处理系统class FileReader:"""文件读取器接口"""def read(self):"""读取文件内容"""passdef close(self):"""关闭文件"""passclass TextFileReader:"""文本文件读取器"""def __init__(self, filename):self.filename = filenameself.content = f"这是文本文件 {filename} 的内容"def read(self):print(f"📄 读取文本文件:{self.filename}")return self.contentdef close(self):print(f"关闭文本文件:{self.filename}")class ImageFileReader:"""图片文件读取器"""def __init__(self, filename):self.filename = filenameself.image_data = f"{filename} 的图片数据"def read(self):print(f"🖼️ 读取图片文件:{self.filename}")return self.image_datadef close(self):print(f"关闭图片文件:{self.filename}")class DatabaseConnection:"""数据库连接(也支持"文件"操作)"""def __init__(self, db_name):self.db_name = db_nameself.data = f"数据库 {db_name} 中的数据"def read(self):print(f"💾 从数据库读取:{self.db_name}")return self.datadef close(self):print(f"关闭数据库连接:{self.db_name}")class WebAPI:"""Web API(也支持"文件"操作)"""def __init__(self, url):self.url = urlself.api_data = f"从 {url} 获取的API数据"def read(self):print(f"🌐 调用API:{self.url}")return self.api_datadef close(self):print(f"关闭API连接:{self.url}")# 鸭子类型的文件处理函数def process_file(file_obj):"""处理"文件"对象 - 使用鸭子类型只要对象有read()和close()方法,就可以被处理"""try:print(f"开始处理:{file_obj.__class__.__name__}")data = file_obj.read() # 调用read方法print(f"处理数据:{data[:50]}...")return datafinally:file_obj.close() # 调用close方法# 创建不同类型的"文件"对象file_objects = [TextFileReader("document.txt"),ImageFileReader("photo.jpg"),DatabaseConnection("user_data"),WebAPI("https://api.example.com/users")]# 鸭子类型:只要有相同的方法,就能被相同的函数处理print("🦆 鸭子类型演示:")for file_obj in file_objects:print("\n" + "="*50)result = process_file(file_obj)print("处理完成")
5.3.5 协议(Protocol)- Python 3.8+
Python 3.8引入了Protocol,提供了更正式的鸭子类型定义:
from typing import Protocolclass Drawable(Protocol):"""可绘制对象协议"""def draw(self) -> None:"""绘制对象"""...def get_area(self) -> float:"""获取面积"""...class Circle:"""圆形 - 实现Drawable协议"""def __init__(self, radius):self.radius = radiusdef draw(self):print(f"绘制半径为{self.radius}的圆形")def get_area(self):import mathreturn math.pi * self.radius ** 2class Square:"""正方形 - 实现Drawable协议"""def __init__(self, side):self.side = sidedef draw(self):print(f"绘制边长为{self.side}的正方形")def get_area(self):return self.side ** 2# 使用协议的函数def render_shape(shape: Drawable):"""渲染形状 - 使用协议类型提示"""shape.draw()print(f"面积:{shape.get_area():.2f}")# 协议不需要显式继承circle = Circle(5)square = Square(4)render_shape(circle) # OKrender_shape(square) # OK
🔄 5.4 高级继承特性
5.4.1 多重继承
Python支持多重继承,即一个类可以继承多个父类:
class Flyable:"""飞行能力"""def __init__(self):self.altitude = 0self.flying = Falsedef take_off(self):self.flying = Trueself.altitude = 100print("起飞!当前高度:100米")def land(self):self.flying = Falseself.altitude = 0print("降落!")def fly_to_altitude(self, target_altitude):if self.flying:self.altitude = target_altitudeprint(f"飞行到高度:{target_altitude}米")class Swimmable:"""游泳能力"""def __init__(self):self.depth = 0self.swimming = Falsedef dive(self):self.swimming = Trueself.depth = 5print("下潜!当前深度:5米")def surface(self):self.swimming = Falseself.depth = 0print("浮出水面!")def swim_to_depth(self, target_depth):if self.swimming:self.depth = target_depthprint(f"游泳到深度:{target_depth}米")class Animal:"""动物基类"""def __init__(self, name):self.name = nameself.energy = 100def eat(self):self.energy = min(100, self.energy + 20)print(f"{self.name}进食,能量:{self.energy}")def rest(self):self.energy = 100print(f"{self.name}休息,能量恢复到满值")# 多重继承:鸭子既能飞又能游泳class Duck(Animal, Flyable, Swimmable):"""鸭子 - 多重继承示例"""def __init__(self, name):Animal.__init__(self, name)Flyable.__init__(self)Swimmable.__init__(self)self.feathers = Truedef quack(self):print(f"鸭子{self.name}:嘎嘎嘎!")def swim_and_fly_demo(self):"""展示多重继承的能力"""print(f"\n🦆 {self.name}的技能演示:")# 游泳技能self.dive()self.swim_to_depth(10)self.surface()# 飞行技能self.take_off()self.fly_to_altitude(200)self.land()# 基本动物行为self.eat()self.quack()# 创建鸭子并演示多重继承duck = Duck("唐老鸭")duck.swim_and_fly_demo()
5.4.2 方法解析顺序(MRO)
当使用多重继承时,Python使用C3线性化算法确定方法解析顺序:
class A:def method(self):print("A的方法")class B(A):def method(self):print("B的方法")super().method()class C(A):def method(self):print("C的方法")super().method()class D(B, C):def method(self):print("D的方法")super().method()# 查看方法解析顺序print("MRO(方法解析顺序):")for i, cls in enumerate(D.__mro__):print(f"{i+1}. {cls.__name__}")print("\n调用D的method():")d = D()d.method()# 实际应用:Mixin模式class LoggerMixin:"""日志混入类"""def log(self, message):class_name = self.__class__.__name__print(f"[{class_name}] {message}")class ValidatorMixin:"""验证混入类"""def validate(self, data):if not data:raise ValueError("数据不能为空")self.log(f"验证通过:{data}")return Trueclass CacheMixin:"""缓存混入类"""def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self._cache = {}def get_from_cache(self, key):if key in self._cache:self.log(f"缓存命中:{key}")return self._cache[key]return Nonedef save_to_cache(self, key, value):self._cache[key] = valueself.log(f"保存到缓存:{key}")class DataProcessor(LoggerMixin, ValidatorMixin, CacheMixin):"""数据处理器 - 使用多个Mixin"""def __init__(self, name):super().__init__()self.name = nameself.log(f"创建数据处理器:{name}")def process(self, data):"""处理数据"""# 检查缓存cached = self.get_from_cache(data)if cached:return cached# 验证数据self.validate(data)# 处理数据result = f"处理结果:{data.upper()}"self.log(f"数据处理完成")# 保存到缓存self.save_to_cache(data, result)return result# 演示Mixin模式processor = DataProcessor("文本处理器")print("\n第一次处理:")result1 = processor.process("hello world")print(f"结果:{result1}")print("\n第二次处理(缓存命中):")result2 = processor.process("hello world")print(f"结果:{result2}")
5.4.3 super()在多重继承中的应用
class Base:def __init__(self, value):self.value = valueprint(f"Base.__init__: {value}")class A(Base):def __init__(self, value, a_param):print(f"A.__init__ 开始")super().__init__(value)self.a_param = a_paramprint(f"A.__init__ 结束")class B(Base):def __init__(self, value, b_param):print(f"B.__init__ 开始")super().__init__(value)self.b_param = b_paramprint(f"B.__init__ 结束")class C(A, B):def __init__(self, value, a_param, b_param, c_param):print(f"C.__init__ 开始")# 使用关键字参数确保正确的参数传递A.__init__(self, value, a_param)B.__init__(self, value, b_param)self.c_param = c_paramprint(f"C.__init__ 结束")# 更好的方式:使用**kwargsclass BetterBase:def __init__(self, value, **kwargs):self.value = valuesuper().__init__(**kwargs)print(f"BetterBase.__init__: {value}")class BetterA(BetterBase):def __init__(self, a_param, **kwargs):self.a_param = a_paramsuper().__init__(**kwargs)print(f"BetterA.__init__: {a_param}")class BetterB(BetterBase):def __init__(self, b_param, **kwargs):self.b_param = b_paramsuper().__init__(**kwargs)print(f"BetterB.__init__: {b_param}")class BetterC(BetterA, BetterB):def __init__(self, c_param, **kwargs):self.c_param = c_paramsuper().__init__(**kwargs)print(f"BetterC.__init__: {c_param}")print("创建C实例:")c = C("test", "a_val", "b_val", "c_val")print("\n创建BetterC实例:")better_c = BetterC(value="test",a_param="a_val",b_param="b_val",c_param="c_val")
💻 5.5 代码示例
示例1:动物园管理系统
from abc import ABC, abstractmethodfrom datetime import datetimeclass Animal(ABC):"""动物抽象基类"""def __init__(self, name, species, age):self.name = nameself.species = speciesself.age = ageself.health = 100self.hunger = 0self.last_fed = None@abstractmethoddef make_sound(self):"""抽象方法:发出声音"""pass@abstractmethoddef get_habitat_type(self):"""抽象方法:获取栖息地类型"""passdef feed(self, food_type):"""喂食"""self.hunger = 0self.health = min(100, self.health + 10)self.last_fed = datetime.now()print(f"给{self.name}喂食{food_type}")def get_info(self):"""获取动物信息"""return {'name': self.name,'species': self.species,'age': self.age,'health': self.health,'hunger': self.hunger}class Mammal(Animal):"""哺乳动物类"""def __init__(self, name, species, age, fur_color):super().__init__(name, species, age)self.fur_color = fur_colordef nurse_young(self):"""哺育幼崽"""print(f"{self.name}正在哺育幼崽")class Bird(Animal):"""鸟类"""def __init__(self, name, species, age, wing_span):super().__init__(name, species, age)self.wing_span = wing_spanself.can_fly = Truedef fly(self):"""飞行"""if self.can_fly:print(f"{self.name}正在飞翔")else:print(f"{self.name}无法飞行")class Lion(Mammal):"""狮子类"""def __init__(self, name, age, mane_length):super().__init__(name, "狮子", age, "金黄色")self.mane_length = mane_lengthdef make_sound(self):return "吼吼吼!"def get_habitat_type(self):return "草原"def hunt(self):print(f"狮子{self.name}正在狩猎")class Eagle(Bird):"""老鹰类"""def __init__(self, name, age, vision_range):super().__init__(name, "老鹰", age, 2.0)self.vision_range = vision_rangedef make_sound(self):return "啸啸啸!"def get_habitat_type(self):return "山地"def hunt_from_sky(self):print(f"老鹰{self.name}从空中俯冲捕猎")class Zoo:"""动物园管理系统"""def __init__(self, name):self.name = nameself.animals = []self.visitors = 0def add_animal(self, animal):"""添加动物"""self.animals.append(animal)print(f"动物园添加了新动物:{animal.name}")def feed_all_animals(self):"""喂食所有动物"""print("🍎 开始给所有动物喂食...")for animal in self.animals:if isinstance(animal, Lion):animal.feed("肉类")elif isinstance(animal, Eagle):animal.feed("鱼类")else:animal.feed("通用食物")def animal_show(self):"""动物表演 - 展示多态"""print("🎪 动物表演开始!")for animal in self.animals:print(f"\n🎭 {animal.name}的表演:")print(f" 叫声:{animal.make_sound()}")print(f" 栖息地:{animal.get_habitat_type()}")# 根据动物类型执行特殊行为if isinstance(animal, Lion):animal.hunt()elif isinstance(animal, Eagle):animal.hunt_from_sky()# 使用动物园管理系统zoo = Zoo("野生动物园")# 添加不同类型的动物lion = Lion("辛巴", 5, "长")eagle = Eagle("雄鹰", 3, 1000)zoo.add_animal(lion)zoo.add_animal(eagle)# 展示多态zoo.feed_all_animals()zoo.animal_show()
示例2:图形用户界面框架
from abc import ABC, abstractmethodclass Widget(ABC):"""GUI组件抽象基类"""def __init__(self, x, y, width, height):self.x = xself.y = yself.width = widthself.height = heightself.visible = Trueself.children = []self.parent = None@abstractmethoddef render(self):"""抽象方法:渲染组件"""passdef add_child(self, child):"""添加子组件"""child.parent = selfself.children.append(child)def show(self):"""显示组件"""self.visible = Trueprint(f"{self.__class__.__name__} 显示")def hide(self):"""隐藏组件"""self.visible = Falseprint(f"{self.__class__.__name__} 隐藏")class Container(Widget):"""容器组件"""def render(self):if self.visible:print(f"渲染容器 ({self.x}, {self.y}, {self.width}x{self.height})")for child in self.children:child.render()class Button(Widget):"""按钮组件"""def __init__(self, x, y, width, height, text, onclick=None):super().__init__(x, y, width, height)self.text = textself.onclick = onclickdef render(self):if self.visible:print(f"渲染按钮 '{self.text}' ({self.x}, {self.y})")def click(self):"""点击事件"""print(f"按钮 '{self.text}' 被点击")if self.onclick:self.onclick()class TextInput(Widget):"""文本输入框"""def __init__(self, x, y, width, height, placeholder=""):super().__init__(x, y, width, height)self.text = ""self.placeholder = placeholderdef render(self):if self.visible:display_text = self.text or self.placeholderprint(f"渲染输入框 '{display_text}' ({self.x}, {self.y})")def set_text(self, text):"""设置文本"""self.text = textprint(f"输入框文本设置为:'{text}'")class Label(Widget):"""标签组件"""def __init__(self, x, y, width, height, text):super().__init__(x, y, width, height)self.text = textdef render(self):if self.visible:print(f"渲染标签 '{self.text}' ({self.x}, {self.y})")# 登录表单示例class LoginForm(Container):"""登录表单"""def __init__(self, x, y):super().__init__(x, y, 300, 200)self.setup_ui()def setup_ui(self):"""设置用户界面"""# 标题title = Label(10, 10, 280, 30, "用户登录")self.add_child(title)# 用户名username_label = Label(10, 50, 80, 25, "用户名:")self.add_child(username_label)self.username_input = TextInput(100, 50, 180, 25, "请输入用户名")self.add_child(self.username_input)# 密码password_label = Label(10, 85, 80, 25, "密码:")self.add_child(password_label)self.password_input = TextInput(100, 85, 180, 25, "请输入密码")self.add_child(self.password_input)# 按钮login_btn = Button(80, 130, 80, 30, "登录", self.login)self.add_child(login_btn)cancel_btn = Button(180, 130, 80, 30, "取消", self.cancel)self.add_child(cancel_btn)def login(self):"""登录处理"""username = self.username_input.textpassword = self.password_input.textprint(f"执行登录:用户名={username}, 密码={'*' * len(password)}")def cancel(self):"""取消处理"""print("取消登录")self.hide()# 使用GUI框架login_form = LoginForm(100, 100)print("渲染登录表单:")login_form.render()print("\n用户输入:")login_form.username_input.set_text("admin")login_form.password_input.set_text("123456")print("\n点击登录按钮:")login_form.children[4].click() # 登录按钮
🏋️♀️ 5.6 练习题
基础练习
练习1:车辆继承体系
设计一个车辆继承体系,包含以下要求:
- 基类
Vehicle:包含品牌、型号、速度等属性 - 子类
Car:添加门的数量、是否为SUV等属性 - 子类
Motorcycle:添加引擎排量、是否为跑车等属性 - 实现多态:不同车辆有不同的启动方式
提示代码框架:
class Vehicle:def __init__(self, brand, model):# 实现基类初始化passdef start(self):# 基类启动方法passdef stop(self):# 基类停止方法passclass Car(Vehicle):def __init__(self, brand, model, doors):# 实现子类初始化passdef start(self):# 重写启动方法pass# 创建不同车辆并测试多态vehicles = [Car("丰田", "卡罗拉", 4), Motorcycle("雅马哈", "R1", 1000)]for vehicle in vehicles:vehicle.start()
练习2:员工管理系统
创建一个员工管理系统,要求:
- 基类
Employee:姓名、工号、基本工资 - 子类
Manager:管理团队大小、奖金计算 - 子类
Developer:编程语言列表、项目奖金 - 子类
Sales:销售额、提成比例 - 实现工资计算的多态
中级练习
练习3:文件处理系统
使用抽象基类设计文件处理系统:
- 抽象基类
FileProcessor:定义处理文件的接口 - 具体类
TextProcessor:处理文本文件 - 具体类
ImageProcessor:处理图片文件 - 具体类
VideoProcessor:处理视频文件 - 每种处理器有不同的处理方法
要求:
- 使用ABC模块创建抽象基类
- 实现多态的文件批处理功能
- 添加文件大小、处理时间等统计信息