五节课掌握 Python 面向对象(以“人狗大战”为例)
第一节课:OOP 入门——创建“人”和“狗”的基本模型
目标:掌握类、对象、实例属性和方法的基础语法,能创建简单的“人”和“狗”并让它们执行基本动作。
-
什么是面向对象?从“人狗大战”理解
- 现实中的“人”和“狗”:有名字、生命值(属性),会攻击、会显示状态(行为)
- 面向对象 vs 面向过程:用“对象”封装属性和行为,逻辑更清晰
-
定义类:画“人”和“狗”的模板
- 类的语法:
class 类名:
(如class Person:
、class Dog:
) - 类的作用:规定对象有哪些属性(名字、生命值)和方法(攻击、显示状态)
- 类的语法:
-
创建对象:造出具体的“人”和“狗”
- 实例化语法:
对象名 = 类名(参数)
(如xiaoming = Person("小明", 100)
) - 访问对象属性:
对象.属性名
(如xiaoming.name
查看名字)
- 实例化语法:
-
用
__init__
方法初始化属性__init__
的作用:对象创建时自动赋值(避免手动逐个设置属性)- 语法:
def __init__(self, 名字, 生命值): self.属性 = 参数
- 示例:创建“小明”时直接设定生命值 100、攻击力 20
-
写实例方法:让“人”和“狗”动起来
- 实例方法语法:
def 方法名(self, 参数):
(self
代表当前对象) - 核心方法实现:
show_status()
:打印“名字:XX,生命值:XX”attack(enemy)
:攻击敌人(敌人生命值减少攻击力)
- 调用方法:
对象.方法名()
(如xiaoming.attack(dog)
)
- 实例方法语法:
-
实战:简单的“人狗互攻”
- 创建“小明”和“旺财”,调用
attack
方法模拟一轮攻击 - 打印攻击后双方的状态
- 创建“小明”和“旺财”,调用
第二节课:封装与继承——让“人狗大战”更合理
目标:掌握封装(保护属性)和继承(复用代码),区分“人”和“狗”的特性差异。
-
封装:保护“生命值”不被随意修改
- 为什么需要封装?防止生命值被改成负数(如
dog.hp = -100
) - 私有属性:用
__属性名
定义(如__hp
),外部无法直接修改 property
装饰器:优雅控制属性访问(读/改都触发校验)- 示例:
@property
定义hp
,修改时自动确保生命值≥0
- 示例:
- 为什么需要封装?防止生命值被改成负数(如
-
继承:减少重复代码,定义“战斗角色”基类
- 问题:“人”和“狗”都有生命值、攻击力,方法重复怎么办?
- 继承语法:
class 子类(父类):
(如class Person(Role):
,Role
是基类) - 父类
Role
的设计:封装“所有战斗角色”的共性(hp
、attack
、is_alive()
)
-
子类定制:“人”和“狗”的独特行为
- 继承父类方法:直接使用父类的
is_alive()
(判断是否存活) - 新增方法:
Person
加use_weapon()
(临时提升攻击力),Dog
加bite()
(特殊攻击) - 方法重写:重写
attack()
让“人挥拳”“狗撕咬”(体现差异)
- 继承父类方法:直接使用父类的
-
super()
函数:调用父类的方法- 作用:在子类中复用父类的
__init__
方法(避免重复写属性初始化) - 示例:
super().__init__(name, hp, attack)
调用父类构造
- 作用:在子类中复用父类的
-
实战:带封装和继承的“人狗大战”
- 用
property
保护生命值,确保攻击后不会出现负数 - 让“小明”用武器提升攻击力,“旺财”用撕咬攻击,验证继承和重写效果
- 用
第三节课:多态与鸭子类型——让战斗角色更灵活
目标:理解多态(同一行为不同实现)和鸭子类型(行为决定类型),支持更多角色加入战斗。
-
多态:“特殊攻击”的不同表现
- 多态的核心:同一方法名,不同实现(人“全力一击”,狗“疯狂撕咬”)
- 实现方式:父类
Role
定义special_attack()
,子类Person
/Dog
分别重写 - 调用:用同一函数
trigger_special(role, enemy)
触发不同效果
-
鸭子类型:不看“出身”,只看“能力”
- 核心逻辑:“像鸭子叫、像鸭子走,就是鸭子”——有战斗方法就是“战斗角色”
- 示例:新增
Cat
类(无继承Role
,但有attack()
),直接加入战斗 - 优势:无需修改原有代码,轻松扩展新角色(如机器人、怪兽)
-
类属性与类方法:统计全局战斗数据
- 类属性:所有实例共享(如
Role.total_fights = 0
统计总战斗次数) - 类方法(
@classmethod
):操作类属性(如Role.update_fights()
每次战斗后+1) - 调用:
Role.total_fights
直接访问,无需创建实例
- 类属性:所有实例共享(如
-
静态方法:战斗中的工具函数
- 作用:封装独立工具(如“暴击判定”“伤害计算”,不依赖类/实例属性)
- 语法:
@staticmethod
装饰,无self
/cls
参数 - 示例:
is_critical()
随机返回是否暴击(30%概率)
-
实战:支持多角色的混战系统
- 加入
Cat
和Robot
角色,用鸭子类型让它们参与战斗 - 用类属性统计总战斗次数,静态方法判定暴击,打印战斗结果
- 加入
第四节课:进阶特性——给“人狗大战”加规则和扩展
目标:掌握特殊方法、动态扩展、__slots__
等进阶语法,增强战斗的灵活性和规范性。
-
特殊方法:让对象交互更自然
__str__
:自定义打印格式(print(xiaoming)
显示“小明(生命值80)”)__call__
:让对象可被调用(xiaoming()
直接显示当前状态)__bool__
:自定义布尔判断(if xiaoming
等价于if xiaoming.is_alive()
)
-
动态扩展:临时给角色加技能或属性
- 动态添加实例属性:
xiaoming.weapon = "剑"
(战斗中临时加武器) - 动态添加实例方法:用
types.MethodType
给“旺财”加dig_hole()
(逃跑技能) - 注意:仅对当前实例生效,不影响其他对象
- 动态添加实例属性:
-
__slots__
属性:限制角色的属性- 作用:防止随意添加无关属性(如给“人”加“翅膀”),节省内存
- 语法:
__slots__ = ("name", "hp", "attack")
限定允许的属性 - 示例:给
Person
加__slots__
,避免误加fly
等无效属性
-
组合:给“人”装备武器和药品
- 组合 vs 继承:“人”可以“拥有”武器(组合,has-a 关系),而非“是”武器(继承)
- 实现:定义
Weapon
类(name
、add_attack
),Person
类中包含weapon
属性 - 效果:装备武器后,攻击力 = 基础攻击力 + 武器加成
-
实战:带装备和临时技能的战斗
- 给“小明”装备“青铜剑”(攻击力+10),动态添加“急救”技能
- 用
__slots__
限制Dog
只能有基础属性,验证特殊方法的交互效果
第五节课:高级应用——战斗系统的规则控制
目标:掌握单例模式、元类等高级工具,实现战斗的全局规则和约束。
-
单例模式:确保只有一个“战斗裁判”
- 需求:整场战斗只有一个裁判,负责判定胜负、记录规则
- 实现:重写
__new__
方法,用_instance
存储唯一实例 - 示例:
Referee.get_instance()
无论调用多少次,都返回同一个裁判对象
-
元类:强制所有战斗角色遵守规则
- 元类的作用:控制类的创建(“类的类”)
- 应用:自定义元类
BattleMeta
,检查所有角色类是否有attack()
方法 - 效果:没实现
attack()
的类,定义时直接报错(确保能战斗)
-
抽象基类(ABC):规范角色接口
- 用
abc
模块定义抽象基类Fighter
,强制子类实现attack()
和is_alive()
- 对比:元类在“类创建时”检查,ABC 在“实例化时”检查
- 适用场景:大型项目中统一接口,避免协作时漏写方法
- 用
-
完整战斗系统整合
- 类结构:
Role
基类 →Person
/Dog
子类 →Weapon
/Medicine
辅助类 - 核心逻辑:裁判主持回合制战斗,支持装备、暴击、特殊攻击
- 数据统计:类属性记录总场次、胜负数,战斗结束后打印报表
- 类结构:
-
实战:多轮“人狗猫机器人”混战
- 验证单例裁判的唯一性,元类对角色的约束
- 扩展功能:加入“药品回血”“武器耐久度”,测试系统的扩展性
-
总结:OOP 核心思想与 Python 特性
- 封装、继承、多态的实战应用
- 动态类型、鸭子类型给 Python 带来的灵活性
- 不同场景下工具的选择(何时用单例、元类、ABC)