Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

当一个类继承自父类时,子类可以拥有自己的实例变量和方法,但有时它仍然需要使用父类代码的部分内容。

这时就用到了 super() 函数。
它让子类能够访问父类的方法(间接访问属性),而无需硬编码父类的名称。

super() 最常见的用法之一是从子类内部调用父类的构造函数__init__),这样父类可以先设置自己的属性,然后子类再添加新的属性。

当你创建一个定义了自己 init 方法的子类时,它会覆盖父类的 init。这意味着当你用子类创建对象时,只有子类的 init 会被调用——父类的构造函数不会自动调用。因此,父类 init 中定义的任何初始化逻辑、默认值或属性都会被完全跳过,导致子类对象中这些属性未定义。如果父类负责重要的初始化工作,这可能会引发意外错误。为避免丢失这部分行为,你应该在子类的构造函数中显式调用 super().init(),这样可以在子类添加或覆盖任何内容之前先执行父类的初始化。

让我们现在来探索一下这个过程!


为什么要使用 super().__init__()

创建子类时,你可能会给它添加额外的数据需要保存。
但是,你仍然希望父类的属性能够被正确初始化。与其重写父类的初始化代码,不如直接用 super().__init__() 调用它。

示例:在子类中添加新属性

假设我们有一个存储 nameageAnimal 类。
我们想要创建一个 Dog 子类,它还保存狗的 breed(品种),但还是想用 Animal 的构造函数来设置 nameage

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用 Animal 的构造函数
        self.breed = breed           # 添加 Dog 自己的属性

逐步解析该过程

  1. 当我们创建一个 Dog 对象时,Python 会运行 Dog 类的 __init__ 方法。
  2. Dog.__init__ 内,super().__init__(name, age) 语句调用了 Animal.__init__
  3. 父类构造函数(Animal.__init__)设置了 self.nameself.age
  4. 控制权回到 Dog.__init__,然后设置了 self.breed

这样:

  • 父类的属性被准确初始化,符合父类的预期。
  • 子类能在不重复代码的情况下添加自己的属性。

使用示例

dog = Dog("Rex", 4, "Golden Retriever")

print(dog.name)   # Rex
print(dog.age)    # 4
print(dog.breed)  # Golden Retriever

为什么 super() 比直接用父类名调用更好

可以直接调用 Animal.__init__(self, name, age),但使用 super() 更灵活:

  • 它自动支持多重继承(如果你的类继承了多个父类)。
  • 维护代码更方便——如果父类名字改了,你无需改所有引用。
  • 清楚地表达出你有意调用父类的方法。
小提示:总是在设置子类自己的属性之前调用 `super().__init__()`,确保所有父类属性都准备好可用。

总结

super() 是你连接父类的桥梁。 使用它可以:

  • 重用父类的初始化代码。
  • 扩展父类功能而不重复代码。
  • 让代码更简洁、易维护,并适应类层次的变化。

下一课我们将探讨私有方法和变量 —— 一种保护类内部数据不被外部访问或修改的方式。