super()
函数的一种常见用途就是继承父类时,调用父类方法,能确保父类被正常初始化。
通常在继承类中我们可以看到直接调用父类中的方法,就像下面这样:
- class Base:
- def __init__(self):
- print("Base = __init__")
-
-
- class A(Base):
- def __init__(self):
- Base.__init__(self)
- 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__")
-
-
- if __name__ == '__main__':
- c = C()
- print(c)
上面的代码运行后,会发现 “ Base = __init__ ”
被调用了两次。就像下面这样:
- Base = __init__
- A = __init__
- Base = __init__
- B = __init__
- C = __init__
- <__main__.C object at 0x000001D51899BE50>
-
- Process finished with exit code 0
当然这样调用并不是不可以,也没有什么害处。但也不排除出现问题的可能性,所以尽量规范去调用,将代码修改为使用super()
后,那么一切工作就能正常工作了(官方推荐使用 “ super().__int__() ”
调用):
- 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__")
-
-
- if __name__ == '__main__':
- c = C()
- print(c)
代码修改为super()
调用并运行后,就会发现每个__init__()
只调用了一次(这种调用是规范的,也是官方推荐的)。就像下面这样:
- Base = __init__
- B = __init__
- A = __init__
- C = __init__
- <__main__.C object at 0x000001B462C9A6B0>
为什么两种调用产生的结果会不一致呢?
首先python的继承时,会计算出一个解析顺序的MRO的只读列表。就像下面这样:
- if __name__ == '__main__':
- print(C.mro())
-
-
- # 运行结果
- [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
-
- Process finished with exit code 0
在MRO
列表中,可看到继承的顺序是先自己本身,继承了两个类的时候是先左后右,如果父类还有继承则再继续找父类的父类,最后再找到原始基类(object
),这也是继承运行的执行顺序。
而“ Base = __init__ ”
被调用了两次的原因是因为A类中继承Base父类,B类中也继承了Base父类,然后C又继承了A、B父类,这个时候运行C类时,C在初始化时分别调用了“ A.__init__(self) ”
和“ B.__init__(self) ”
,最后结果就必然会产生Base基类被多次调用的效果了。
当修改为“ super().__init__() ”
时,没有产生多次调用的原因则是每个类在初始化时都进行了super(
)的重新定义后的方法覆盖(也就是重写),自然就不会出现多次调用的效果了。
今天先聊到这里吧,以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的一键 3 连【 点赞、收藏、分享 】哟,谢谢!
未完成,待续……
一直在努力,希望你也是!
微信搜索公众号:就用python