在Python面向对象编程中,我们经常需要调用父类的构造函数,而调用父类构造函数的一种常用方法是使用super()函数,其搭配的关键字是__init__()函数。
一、super()函数的概念
super()函数用于调用父类中的方法,可以避免在子类实现中重复写出父类的方法名,实现了代码复用与维护的便利。
当父类中出现同名函数的时候,使用super()可以保证调用了正确的函数。这是因为super()会按照方法解析顺序(MRO)的顺序来查找父类中的方法,而不是在当前类中查找。
MRO是一种线性化的方法解析顺序,它定义了子类中的方法搜索顺序,每个类都有一个MRO列表,按照从左至右,深度优先的顺序排列。
class A:
def __init__(self):
print('调用A类构造函数')
class B(A):
def __init__(self):
super().__init__()
print('调用B类构造函数')
b = B()
运行结果:
调用A类构造函数 调用B类构造函数
上例中,子类B继承自父类A,并在构造函数中调用了父类A的构造函数。在调用super().__init__()时,会调用父类A的构造函数,输出“调用A类构造函数”的信息,然后再执行自身的构造函数,输出“调用B类构造函数”的信息。
二、super()函数使用时应注意的问题
1. super()函数的参数
super()函数有两种常见的调用形式,一种是super(当前类名, self);另一种是super(父类名, 子类实例)。
第一种调用形式中,当前类名可以省略,直接传入self,Python解释器会自动根据当前类确定要调用的父类。
class A:
def foo(self):
print('调用A类方法')
class B(A):
def foo(self):
super().foo()
b = B()
b.foo()
运行结果:
调用A类方法
上例中,子类B继承自父类A,重写了foo方法,并在foo方法中使用super().foo()调用了父类A的foo方法。
第二种调用形式中,可以手动指定要调用的父类名称,Python解释器会根据该名称按照类的继承关系来确定要调用的父类。
class A:
def foo(self):
print('调用A类方法')
class B(A):
def foo(self):
super(A, self).foo()
b = B()
b.foo()
运行结果:
调用A类方法
上例中,子类B继承自父类A,重写了foo方法,并在foo方法中使用super(A, self).foo()调用了父类A的foo方法。
2. super()函数与多继承的关系
在多继承的情况下,使用super()函数调用的是MRO列表中的下一个类的方法,而不是当前类的父类的方法。
class A:
def foo(self):
print('调用A类方法')
class B:
def foo(self):
print('调用B类方法')
class C(A, B):
def foo(self):
super().foo()
c = C()
c.foo()
运行结果:
调用B类方法
上例中,子类C继承自父类A和B,并在foo方法中使用super().foo()调用了父类A和B的foo方法。在Python中,多继承使用DFS算法创建MRO列表。因此MRO列表中的顺序为[C, A, B, object],super()函数调用的是MRO列表中的下一个类的方法,即B类的foo方法。
三、总结
super()函数是Python中非常重要的一个函数,用于调用父类的方法。在使用时应注意其参数的传入方式,以及在多继承的情况下的使用。
合理使用super()函数可以提高代码的可读性、减少代码重复和维护成本,是每个Python工程师都需要掌握的基本技能。