调用父类中的方法

转载须注明出处:简书@Orca_J35
可参考另外两则笔记:方法解析顺序(MRO) | super()

子类中的方法会覆盖父类中的同名方法,如果需要调用父类中的方法,可以采用以下两种方式:

  1. 通过父类名称来调用父类中方法:

    <parent class name>.<method name>(self, <other arguments>)
    
  2. 构造一个 super 对象,并通过该对象调用父类中的方法。这种方法的优点在于无需显式引用父类,从而使代码更容易维护;并且在"钻石形"多继承的类层次结构中可避免重复调用父类中的方法。

在单继承的类层次结构中,上述两种方法并没有太显著的区别。super 的优点在于无需显式引用父类,从而使代码更容易维护。比如,在子类中调用父类的 __init__() 方法,以确保正确初始化:

class Base:
    def __init__(self, arg):
        print('Base.__init__')

class A(Base):
    def __init__(self, arg):
        Base.__init__(self, arg) # 等效于 super().__init__(arg)
        print('A.__init__')

在"钻石形"多继承的类层次结构中,如果直接引用父类名称,则可能会重复调用父类中的方法。比如,考虑如下的情况:

class Base:
    def __init__(self):
        print('Base.__init__')

class A(Base):
    def __init__(self):
        Base.__init__(self)
        print('A.__init__')

class B(Base):
    def __init__(self):
        Base.__init__(self)
        print('B.__init__')

class C(A,B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)
        print('C.__init__')

如果你运行这段代码就会发现 Base.__init__() 被调用两次,如下所示:

>>> c = C()
Base.__init__
A.__init__
Base.__init__
B.__init__
C.__init__
>>>

两次调用 Base.__init__() 通常没有什么坏处,但有时却会出现意外。如果我们在代码中使用 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__()  # Only one call to super() here
        print('C.__init__')

运行这个新版本后,你会发现每个 __init__() 方法只会被调用一次了:

>>> c = C()
Base.__init__
B.__init__
A.__init__
C.__init__
>>>

为了弄清 super() 的原理,这里需要补充一个知识点:方法解析顺序(MRO) 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容