在 Python 的面向对象编程中,继承允许一个类从另一个类中继承特性和行为,而
super() 是一个内置函数,用于调用父类的方法,使得子类可以访问父类的初始化方法或其他方法,从而扩展或修改父类的方法行为。
super() 的基本用法
- 调用父类的初始化方法:在子类中 super() 可用于调用父类的构造函数,确保父类的初始化部分也被正确执行。
- 方法重载与扩展:当重定义一个在父类中已有的方法时,可使用 super() 去调用父类的方法,继而扩展其功能。
- 多重继承中的线性化顺序:super() 会按照方法解析顺序(Method Resolution Order,
MRO)来寻找合适的父类方法,确保多重继承中的方法调用顺序问题。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} makes a sound")
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类的 __init__ 方法
super().__init__(name)
self.breed = breed
def speak(self):
# 使用super调用父类的speak方法
super().speak()
print(f"{self.name} barks")
# 测试代码
dog = Dog("Buddy", "Golden Retriever")
print(dog.name) # Outputs: Buddy
print(dog.breed) # Outputs: Golden Retriever
dog.speak()
# Outputs:
# Buddy makes a sound
# Buddy barks
代码解释
- 父类 Animal:
__init__方法接受一个 name,并将其存储在实例属性中。- speak 方法输出动物会发出的声音。
- 子类 Dog:
__init__方法扩展了父类的初始化,添加了 breed(狗品种)这一额外属性。- 使用
super().__init__(name)调用父类的初始化方法,确保 name 也被正确赋值。
重写了 speak 方法,利用 super().speak() 调用父类的 speak 方法,然后添加额外的行为(打印狗的叫声)。
super() 在多重继承中的应用
当面对多重继承时,super() 是一个非常有用的工具,因为它可以依赖 MRO 来正确调用方法。这会变得较为复杂,但 super() 可以简化这一过程,使得代码更为清晰
class Base:
def __init__(self):
print("Base init")
class A(Base):
def __init__(self):
super().__init__()
print("A init")
class B(Base):
def __init__(self):
super().__init__()
print("B init")
class C(A, B):
def __init__(self):
super().__init__()
print("C init")
# 实例化 C
c = C()
# Outputs:
# Base init
# B init
# A init
# C init
# C类的MRO:C -> A -> B -> Base
# 所以super()会按照这个顺序调用方法
MRO 顺序
在多重继承中,Python 使用 C3 线性化(C3 superclass linearization)算法来计算 MRO。这个算法遵循以下原则:
- 子类会先于父类被检查。
- 如果有多个父类,会根据它们在类定义中出现的顺序进行检查。
- 第一个满足方法解析规则的类的方法被调用。
对于这个例子,类 C 的 MRO 顺序是:C -> A -> B -> Base。原因如下:
-
C 直接继承自 A 和 B,所以 C 先是 A,然后是 B。
-
然后检查A的继承链,A直接继承自 Base,所以添加 Base。
-
最后是 B 的继承链,已经在 A 中考虑 Base,因此不会重复。
这样得到了以下 MRO 顺序:
C -> A -> B -> Base
执行顺序
在创建 C 的实例时,调用顺序为:
- C.
__init__() 调用 super().__init__(),根据 MRO,转到 A.__init__()。 - A.
__init__() 调用 super().__init__(),根据 MRO,继续转到 B.__init__()。 - B.
__init__() 调用 super().__init__(),根据 MRO,转到 Base.__init__() - Base.
__init__() 运行,打印 “Base init”。 - 返回到 B.
__init__(), 打印 “B init”。 - 返回到 A.
__init__(), 打印 “A init”。 - 返回到 C.
__init__(), 打印 “C init”。
1206

被折叠的 条评论
为什么被折叠?



