28·模块七:面向对象编程进阶

继承与方法重写

oopinheritanceoverride

第28课:继承与方法重写

学习目标

  1. 理解继承的概念:能够解释什么是类继承,以及它如何帮助实现代码复用和建立类层次结构。
  2. 掌握方法重写的语法与目的:学会在子类中重新定义父类的方法,并理解其在实际编程中的应用场景。
  3. 学会调用父类方法:能够使用super()函数在子类中安全、正确地调用被重写的父类方法,实现功能的扩展而非完全替换。

核心概念

1. 什么是继承?

想象一下,你有一个"交通工具"的基类,它定义了所有交通工具都具有的属性(如颜色、速度)和方法(如启动、停止)。现在,你想创建"汽车"和"飞机"两个类。它们都是交通工具,但又有自己独特的特性(汽车有轮子,飞机有翅膀)。与其从头开始写"汽车"和"飞机"类,不如让它们继承"交通工具"类。

  • 父类(Parent Class / Base Class):被继承的类(如 交通工具)。
  • 子类(Child Class / Derived Class):继承而来的类(如 汽车)。
  • 继承关系:子类自动拥有父类所有公开的属性和方法,并可以在此基础上进行扩展修改

继承最大的好处是代码复用建立逻辑层次。我们不需要在每个子类中重复编写相同的代码。

2. 什么是方法重写?

继承之后,子类拥有了父类的方法。但是,子类可能觉得父类的某个方法行为不太符合自己的需求。例如,父类 动物 有一个 speak() 方法打印"...",但子类 希望 speak() 方法打印"汪汪汪"。这时,我们就可以在子类中重新定义一个与父类同名的方法,这个过程就叫做方法重写(Override)

重写后,当你通过子类对象调用该方法时,会优先执行子类重写后的版本,而不是父类的版本。

代码示例

示例1:基本的继承与方法重写

# 定义一个父类:动物 (Animal)
class Animal:
    def __init__(self, name):
        self.name = name  # 所有动物都有名字

    def speak(self):
        """父类的 speak 方法,提供一个通用实现"""
        print(f"{self.name} 发出了一些声音。")

# 定义一个子类:狗 (Dog),继承自 Animal
class Dog(Animal):
    def speak(self):
        """重写父类的 speak 方法,实现狗特有的行为"""
        print(f"{self.name} 说:汪汪汪!")

# 定义另一个子类:猫 (Cat),继承自 Animal
class Cat(Animal):
    def speak(self):
        """重写父类的 speak 方法"""
        print(f"{self.name} 说:喵喵喵~")

# 测试继承和重写
if __name__ == "__main__":
    # 创建一个通用的动物对象
    generic_animal = Animal("小动物")
    generic_animal.speak()  # 调用父类的方法

    # 创建狗和猫的对象
    dog = Dog("阿黄")
    cat = Cat("咪咪")

    dog.speak()  # 调用 Dog 类重写后的 speak 方法
    cat.speak()  # 调用 Cat 类重写后的 speak 方法

    # 子类对象同样拥有父类的属性
    print(f"这只狗的名字是:{dog.name}")

输出:

小动物 发出了一些声音。
阿黄 说:汪汪汪!
咪咪 说:喵喵喵~
这只狗的名字是:阿黄

示例2:在重写的方法中调用父类方法(使用 super()

有时,我们不想完全抛弃父类方法的功能,而是希望在它基础上进行扩展。这时可以使用 super() 函数。

class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound  # 动物的基本叫声

    def introduce(self):
        """一个介绍自己的方法"""
        print(f"我是一只{self.name},我的叫声是'{self.sound}'。")

class Parrot(Animal):  # 鹦鹉类
    def __init__(self, name, sound, color):
        # 先调用父类的 __init__ 方法,完成基本属性的初始化
        super().__init__(name, sound)
        # 然后添加子类独有的属性
        self.color = color  # 鹦鹉的颜色

    def introduce(self):
        """重写 introduce 方法,并扩展它"""
        # 调用父类的 introduce 方法,执行原有的介绍逻辑
        super().introduce()
        # 然后添加子类特有的介绍内容
        print(f"我有漂亮的{self.color}羽毛。")

# 测试
parrot = Parrot("波利", "嘎嘎", "红绿")
parrot.introduce()

输出:

我是一只波利,我的叫声是'嘎嘎'。
我有漂亮的红绿羽毛。

实践练习

练习1:基础重写

  1. 创建一个父类 Vehicle,包含属性 brand(品牌)和方法 describe()describe() 方法打印 "这是一个 [品牌] 交通工具。"
  2. 创建一个子类 Car,继承自 Vehicle
  3. Car 类中重写 describe() 方法,使其打印 "这是一辆 [品牌] 品牌的汽车。"
  4. 创建一个 Car 对象并调用其 describe() 方法。

预期输出:

这是一辆 宝马 品牌的汽车。

练习2:使用 super() 扩展方法

  1. 创建一个父类 BankAccount,包含属性 owner(户主)和 balance(余额,初始值为0)。包含方法 deposit(amount) 用于存款。
  2. 创建一个子类 InterestAccount,继承自 BankAccount。它新增一个属性 rate(利率,如0.05代表5%)。
  3. InterestAccount 中重写 deposit(amount) 方法:首先调用父类的 deposit 方法完成存款,然后计算并加上利息(利息 = 存款额 * 利率),最后打印 "存款成功,并计算利息:[利息金额] 元。当前总余额:[总余额] 元。"
  4. 创建一个 InterestAccount 对象,存款1000元,观察输出。

预期输出:

存款成功,并计算利息:50.0 元。当前总余额:1050.0 元。

练习3:综合应用

  1. 设计一个 Shape (形状) 类,包含一个方法 area() 用于计算面积(这里可以先返回0或抛出一个 NotImplementedError 表示这是一个需要子类实现的方法)。
  2. 创建子类 Rectangle (矩形),拥有 widthheight 属性,并重写 area() 方法计算矩形面积。
  3. 创建子类 Circle (圆),拥有 radius 属性,并重写 area() 方法计算圆面积(π * r²,π可用 3.14)。
  4. 分别创建 RectangleCircle 对象,并打印它们的面积。

常见错误

  1. 忘记调用父类的 __init__ 方法:如果子类重写了 __init__ 方法,但没有调用 super().__init__(),那么父类中的属性(如示例2中的 namesound)就不会被初始化,导致后续访问时报 AttributeError

    class Dog(Animal):
        def __init__(self, name, trick):
            # 错误!没有调用 super().__init__(name),导致 self.name 未定义
            self.trick = trick
    
  2. super() 调用方法参数传递错误:在调用 super().method() 时,必须正确传递所需的参数。

    class B(A):
        def method(self, x, y):
            # 错误!父类 method 可能也需要 x 和 y 参数
            super().method() # 这样调用可能因参数不足而失败
    
  3. 试图在子类中访问父类的私有属性:父类中以双下划线 __ 开头的属性是私有的,子类无法直接访问。如果父类提供了公共的访问器(getter)方法,应通过该方法访问。

    class Parent:
        def __init__(self):
            self.__secret = 100  # 私有属性
    class Child(Parent):
        def reveal(self):
            print(self.__secret) # 错误!AttributeError
    

小结

本课我们学习了面向对象编程中两个紧密相关的重要概念:

  • 继承:子类获得父类的属性和方法,实现了代码的复用,并建立了类之间的"是一个(is-a)"关系(例如,狗是一个动物)。
  • 方法重写:子类可以重新定义从父类继承来的方法,以实现特定于子类的行为。这允许我们对父类的功能进行定制覆盖
  • super() 函数:它是子类中调用父类方法的桥梁,尤其在重写方法时,用于扩展而非完全替换父类功能,保证了代码的连贯性和正确性。

掌握继承和重写,是构建灵活、可维护的大型程序的基石。它让我们的类结构层次分明,逻辑清晰。在下一课,我们将学习多态,它正是建立在继承和重写之上的更强大特性。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「多态与鸭子类型」 以巩固所学知识。