欢迎来到 Python 学习计划的第 39 天!🎉
恭喜你!昨天我们完成了 OOP 基础阶段(第 34-38 天) 的学习,掌握了类与对象、属性、方法以及生命周期管理。
从今天开始,我们将进入 OOP 核心阶段(第 39-42 天),深入探讨面向对象编程的 三大特征:继承、封装、多态。
今天是核心阶段的第一天,我们将重点学习 继承(Inheritance) 的基本概念与 单继承 语法。这是代码复用的基石!
一、OOP 三大特征简介
面向对象编程之所以强大,主要归功于以下三大特征。今天我们先概览,后续几天会逐一深入。特征 | 英文 | 核心思想 | 比喻 | 学习日程 |
|---|
继承 | Inheritance | 代码复用,建立类之间的层次关系 | 子女继承父母的特征 | 第 39-40 天 |
封装 | Encapsulation | 隐藏细节,保护数据安全 | 手机内部电路封装在外壳里 | 第 42 天 |
多态 | Polymorphism | 同一接口,不同实现 | 动物叫:狗汪汪,猫喵喵 | 第 41 天 |
二、什么是继承(Inheritance)?
1. 定义
继承 是指一个类(子类/派生类)可以获取另一个类(父类/基类)的属性和方法。
2. 为什么要使用继承?
- 代码复用:避免重复编写相同的代码。
- 建立层次关系:模拟现实世界的"Is-A"关系(如:Dog Is-A Animal)。
- 扩展功能:在父类基础上添加新功能,而不修改父类代码。
3. 基本语法
class 父类: passclass 子类 (父类): pass
示例:动物与狗
class Animal: def __init__(self, name): self.name = name def speak(self): print("动物发出声音")# Dog 继承 Animalclass Dog(Animal): passd = Dog("旺财")print(d.name) # 旺财 (继承了父属性)d.speak() # 动物发出声音 (继承了父方法)
✅ 关键点:子类自动拥有父类的所有公共属性和方法。三、单继承基本语法详解
Python 支持单继承(一个子类只有一个父类)和多继承(后续学习)。今天先掌握单继承。
1. 子类调用父类构造函数
如果子类定义了 __init__,父类的 __init__不会自动调用。必须显式调用。
❌ 错误写法
class Cat(Animal): def __init__(self, name, color): # 忘记调用父类 __init__ self.color = color # self.name 未定义!c = Cat("小白", "白色")# print(c.name) # ❌ AttributeError
✅ 正确写法(使用 super())
class Cat(Animal): def __init__(self, name, color): super().__init__(name) # 调用父类构造函数 self.color = color # 子类特有属性c = Cat("小白", "白色")print(c.name) # 小白 (来自父类)print(c.color) # 白色 (来自子类)
2. 为什么推荐 super()?
- 可维护性:如果父类名改变,不需要修改子类代码。
- 多继承友好:在多继承中,
super() 能正确处理 MRO(方法解析顺序)。
四、方法重写(Method Overriding)
子类可以重新定义父类的方法,以改变其行为。这叫 方法重写。
示例:不同的叫声
class Animal: def speak(self): print("动物发出声音")class Dog(Animal): # 重写父类方法 def speak(self): print(f"{self.name} 说:汪汪汪!")class Cat(Animal): # 重写父类方法 def speak(self): print(f"{self.name} 说:喵喵喵!")d = Dog("旺财")c = Cat("小白")d.speak() # 旺财 说:汪汪汪!c.speak() # 小白 说:喵喵喵!
💡 核心思想:父类定义通用接口,子类提供具体实现。这是 多态 的基础。
五、扩展父类方法
有时我们不想完全覆盖父类方法,而是想在父类功能基础上 增加 功能。
示例:记录说话次数
class Animal: def __init__(self, name): self.name = name self.speak_count = 0 def speak(self): self.speak_count += 1 print("动物发出声音")class Dog(Animal): def speak(self): # 1. 先调用父类方法(记录次数) super().speak() # 2. 再增加子类特有行为 print("尾巴摇摆")d = Dog("旺财")d.speak()# 输出:# 动物发出声音# 尾巴摇摆print(d.speak_count) # 1 (父类属性被修改)
六、属性的继承与查找顺序
结合第 36 天学的 类属性 vs 实例属性,继承中的属性查找顺序如下:
- 实例属性(对象自己的
__dict__) - 子类类属性(子类自己的
__dict__) - 父类类属性(父类的
__dict__)
示例:属性查找链
class Parent: species = "生物" # 父类类属性 def __init__(self): self.age = 10 # 父类实例属性class Child(Parent): species = "人类" # 子类类属性(遮蔽父类) def __init__(self): super().__init__() self.name = "孩子" # 子类实例属性c = Child()print(c.name) # 孩子 (子类实例属性)print(c.age) # 10 (父类实例属性,通过 super 初始化)print(c.species) # 人类 (子类类属性优先)print(Parent.species) # 生物 (父类类属性未变)
⚠️ 注意:如果子类 __init__ 中没有调用 super().__init__(),则不会继承父类的 实例属性。
七、常见误区与注意事项
1. 混淆 "Is-A" 与 "Has-A"
- 继承 (Is-A):狗 是 动物。✅ 用继承。
- 组合 (Has-A):汽车 有 发动机。❌ 不用继承,用属性。
# ❌ 错误:Engine 不应该继承 Carclass Engine(Car): pass# ✅ 正确:Car 拥有 Engineclass Car: def __init__(self): self.engine = Engine()
2. 忘记调用 super().__init__()
导致父类初始化的属性缺失。
3. 循环继承
A 继承 B,B 继承 A。会导致 RecursionError 或导入错误。
4. 过度继承
继承层次过深(如超过 3 层),会导致代码难以维护。优先考虑 组合。
八、实战练习
练习 1:员工管理系统
创建一个 Employee 类和一个 Manager 类。
Employee:属性 name, salary;方法 work() 打印 "正在工作"。Manager:继承 Employee,增加属性 team;重写 work() 打印 "正在管理团队",并调用父类 work()。
class Employee: def __init__(self, name, salary): self.name = name self.salary = salary def work(self): print(f"{self.name} 正在工作")class Manager(Employee): def __init__(self, name, salary, team): super().__init__(name, salary) self.team = team def work(self): print(f"{self.name} 正在管理 {self.team} 团队") super().work() # 调用父类方法m = Manager("Alice", 10000, "开发组")m.work()# 输出:# Alice 正在管理 开发组 团队# Alice 正在工作
练习 2:图形面积计算
创建一个 Shape 类和一个 Rectangle 类。
Shape:方法 area() 返回 0。Rectangle:继承 Shape,属性 width, height;重写 area() 返回 宽×高。
class Shape: def area(self): return 0class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.heightrect = Rectangle(5, 3)print(rect.area()) # 15
九、总结
知识点 | 说明 |
|---|
继承 | 子类复用父类属性和方法,建立 "Is-A" 关系 |
语法 | class Child(Parent):
|
super()
| 调用父类方法,推荐用于 __init__ |
方法重写 | 子类定义与父类同名方法,覆盖父类行为 |
属性继承 | 实例属性需 super().__init__() 才能继承 |
查找顺序 | 实例 → 子类类 → 父类类 |
明日预告:多重继承与 MRO
明天我们将进入 OOP 核心阶段第二天!
- 主题:多重继承与 MRO(方法解析顺序)
- 核心问题:
- Python 支持一个子类继承多个父类吗?
- 如果多个父类有同名方法,优先调用谁的?
- 什么是 MRO(Method Resolution Order)?
- 什么是菱形继承问题?
- 如何查看类的继承顺序?
💡 提前思考:如果 class D(B, C),而 B 和 C 都继承自 A,调用 D 的方法时,Python 会按什么顺序查找?
掌握单继承,是理解复杂类层次结构的第一步!继续加油!🚀