本文共 2736 字,大约阅读时间需要 9 分钟。
子类中调用父类的方法可以使用super
函数
class A: def func(self): print('A.func') class B(A): def func(self): print('B.func') super().func() print(A().func())print(B().func())
结果为
A.funcNoneB.funcA.funcNone
注意super()
这种写法是在python3
里面的,如果python2
的话你要这样用super(B, self)
。当然在这里你同样可以这样去做
class B(A): def func(self): print('B.func') A.func(self)
同样没有任何问题。
好,那么问题就出现了。同样可以解决问题,python
中为什么要出现super()
呢?
我们看这样一个问题,我们的类的继承关系是一种菱形继承
Base / \ / \ A B \ / \ / C
代码是这样的
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__')print(C())
输出结果是
Base.__init__A.__init__Base.__init__B.__init__C.__init__<__main__.C object at 0x000001A493AF6358>
这显然和你想象中的输出不一样,我们看到 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__() print('C.__init__')
结果是
Base.__init__B.__init__A.__init__C.__init__<__main__.C object at 0x000001A493ACFE10>
嗯,这个结果是我们大多数人想要的。
那么我们就要想,为什么会这样呢?
我们每定义一个类,python
会创建一个MRO
列表,用来管理类的继承信息(你可以把它简单的理解为一个列表)。
C.__mro__Out[14]: (__main__.C, __main__.A, __main__.B, __main__.Base, object)
python
通过这个列表从左到右的顺序,查找类的继承信息。这个列表是通过C3
线性算法实现的,这个算法我们不去讨论,这里我们只要知道有这个表就可以了。
接着回到super()
函数问题。我们可以通过这样的形式调用super(cls, inst)
,这也是我们上面python2
里使用的方案。这里的cls
是一个类,inst
可以是一个类也可以是一个对象。我们通过inst
获取MRO
列表。然后再这个列表中查找cls
类,返回类cls
后面一个类的信息。例如
class C(A,B): def __init__(self): super(C, self).__init__() print('C.__init__')print(C())
这里我们获取到临时对象C()
的MRO
列表
(__main__.C, __main__.A, __main__.B, __main__.Base, object)
返回类C
后面类A
的信息,调用super(A, self).__init__
。因为self
还是C
,MRO
表不变,所以我们接着调用类A
后的类B
,super(B, self).__init__
。同理接着调用super(Base, self).__init__
,也就输出了Base.__init__
。B
中的super().__init__()
执行完后,会执行print('B.__init__')
。然后就是你看到的打印结果。
我这里要强调的是,如果你这里A
类中使用的不是super().__init__
,而是使用A.__init__
,那么结果会像之前那样会出人意料。因为前者在调用时,传入的inst
是C
对象,而后者传入的是A
类。这两者的MRO
列表不同,所以就会出现不同的结果,为了你更好的理解我这里列出A
和B
的MRO
表。
A.__mro__Out[15]: (__main__.A, __main__.Base, object)B.__mro__Out[16]: (__main__.B, __main__.Base, object)
你可以借此去推导,前面出现两次Base.__init__
的原因。
虽然我的这篇文章貌似把super
说的很明白了,但是我强烈建议你去读一下我的这篇文章,你会发现上面很多的东西都是有待商榷的QAQ!!!
当然这是我的理解,可能有不对之处,欢迎大家指出!
转载地址:https://coordinate.blog.csdn.net/article/details/79487433 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!