Python基础:面向对象编程 (OOP)
继承 第二部分: super()
Lesson 4 of 7 • 10 XP
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__() 调用它。
示例:在子类中添加新属性
假设我们有一个存储 name 和 age 的 Animal 类。
我们想要创建一个 Dog 子类,它还保存狗的 breed(品种),但还是想用 Animal 的构造函数来设置 name 和 age。
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 自己的属性
逐步解析该过程
- 当我们创建一个
Dog对象时,Python 会运行Dog类的__init__方法。 - 在
Dog.__init__内,super().__init__(name, age)语句调用了Animal.__init__。 - 父类构造函数(
Animal.__init__)设置了self.name和self.age。 - 控制权回到
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() 是你连接父类的桥梁。
使用它可以:
- 重用父类的初始化代码。
- 扩展父类功能而不重复代码。
- 让代码更简洁、易维护,并适应类层次的变化。
下一课我们将探讨私有方法和变量 —— 一种保护类内部数据不被外部访问或修改的方式。