Python内置函数super()的作用详解用最简单的例子把函数super()的作用和运行过程说清楚)

Posted 昊虹图像算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python内置函数super()的作用详解用最简单的例子把函数super()的作用和运行过程说清楚)相关的知识,希望对你有一定的参考价值。

函数super()用于子类调用父类(超类)的方法。

你肯定要问为什么在子类中在要用函数super()去调用父类中的方法呢?

我像下面这样用不行么?

class A:
    def fun1(self):
        print('Enter A')


class B(A):
    def fun1(self):
        A.fun1(self)
        print('Enter B')


object1 = B()
object1.fun1()

运行结果如下:

是,的确是可以像上面这样,但是这样做的缺点是,当一个子类的父类发生变化时(如类B的父类由A变为C时),必须遍历整个B类的定义,把所有的相关调用名全修改过来。
上面是例子很简单,只有一处需要修改,上面的缺点并不足以成为问题,但是当代码量庞大时,这样的修改可能是灾难性的。
Python中向我们提供了内置函数super()来克服这个缺点和问题,来看一个使用内置函数super()来调用父类方法的示例。

class A:
    def fun1(self):
        print('Enter A')


class B(A):
    def fun1(self):
        super(B, self).fun1()
        print('Enter B')


object1 = B()
object1.fun1()

运行结果如下:

通过上面的代码,我们可以看出,如果类B的父类A改为了C,则只需要把类定义中的第一句语句:

class B(A):

改为

class B(C):

就行了,而不用更改相关的调用语句。

在Python3中,语句

super(B, self).fun1()

可以简写为:

super().fun1()

从上面来看,函数super()虽然把父类的名字隐去了,使得调用父类的方法与父类的名字无关,但是也带来了问题。什么问题呢?看下面的例子:

class A:
    def fun1(self):
        print('Enter A')


class B(A):
    def fun1(self):
        A.fun1(self)
        print('Enter B')


class C(A):
    def fun1(self):
        A.fun1(self)
        print('Enter C')


class D(B, C):
    def fun1(self):
        B.fun1(self)
        print('Enter D')


object1 = D()
object1.fun1()

通过上面的代码,我们可以很清晰地看出子类D有两个父类B和C,即D是一种多重继承。在D中调用的方法fun1()是父类B中的方法fun1(),所以运行结果如下:

但我们若用函数super隐去父类名,这就出问题了,代码如下:

class A:
    def fun1(self):
        print('Enter A')


class B(A):
    def fun1(self):
        super().fun1()
        print('Enter B')


class C(A):
    def fun1(self):
        super().fun1()
        print('Enter C')


class D(B, C):
    def fun1(self):
        super().fun1()
        print('Enter D')


object1 = D()
object1.fun1()

上面的代码存在的问题就是类D对父类中fun1的调用不知道该去调用哪个父类中的fun1。函数super()是这样处理这个问题的:采用MRO顺序把所有解析到的父类fun1都运行一遍且每个找到的方法fun1只运行一次。
我们可以用下面这条语句把类D的MRO顺序打印出来:

print(D.__mro__)

示例代码如下:

class A:
    def fun1(self):
        print('Enter A')


class B(A):
    def fun1(self):
        super().fun1()
        print('Enter B')


class C(A):
    def fun1(self):
        super().fun1()
        print('Enter C')


class D(B, C):
    def fun1(self):
        super().fun1()
        print('Enter D')


print(D.__mro__)  # 把类D的MRO顺序打印出来

运行结果如下:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

根据上面的MRO顺序,我们可以知道类D查询某方法的顺序为类D→类B→类C→类A。
根据以上顺序,我们有以下关于object1.fun1()这条语句的执行过程:
object1.fun1()的第一条需要执行的语句为类D中的语句super().fun1(),这条语句在执行后:
首先在类D中找寻方法fun1(),找到了,找到之后将类D中的方法fun1()编号为①
然后在类B中找寻方法fun1(),找到了,找到之后将类B中的方法fun1()编号为②
然后在类C中找寻方法fun1(),找到了,找到之后将类C中的方法fun1()编号为③
然后在类A中找寻方法fun1(),找到了,找到之后将类A中的方法fun1()编号为④
然后按照④→③→②→①的顺序依次执行一遍一个四个fun1()
当执行④时,函数体唯一的一条语句“print(‘Enter A’)”打印出字符串Enter A
④执行完后执行③,当执行③时,第一条语句为super().fun1(),于是按下面的顺序去搜索fun1:

首先在类C中找寻方法fun1(),找到了,找到之后发现类C中的方法fun1()已经被编号为③
然后在类A中找寻方法fun1(),找到了,找到之后发现类A中的方法fun1()已经被编号为④
然后按照④→③的顺序依次执行一遍一个两个fun1(),正准备执行④的时候,发现④已经被执行过一次了,所以不再执行④,于是直接执行③,执行③的时候发现其第一条语句super().fun1()已经被执行过一次了,所以不再执行这条语句,于是执行语句print(‘Enter C’),打印出字符串Enter C,至此③执行完毕。
③执行完后执行②,当执行②时,第一条语句为super().fun1(),于是按下面的顺序去搜索fun1:

首先在类B中找寻方法fun1(),找到了,找到之后发现类B中的方法fun1()已经被编号为②
然后在类A中找寻方法fun1(),找到了,找到之后发现类A中的方法fun1()已经被编号为④
然后按照④→②的顺序依次执行一遍一个两个fun1(),正准备执行④的时候,发现④已经被执行过一次了,所以不再执行④,于是直接执行②,执行②的时候发现其第一条语句super().fun1()已经被执行过一次了,所以不再执行这条语句,于是执行语句print(‘Enter B’),打印出字符串Enter B。
②执行完后执行①,当执行①时,第一条语句为super().fun1(),这条语句已经被执行过了,所以不再执行这条语句,于是执行剩下的一条语句print(‘Enter D’),打印出字符串Enter D。
综上,输出信息应该如下:
Enter A
Enter C
Enter B
Enter D
我们看下程序的运行结果是不是这样的:

从上面的截图来看,程序实际运行的结果和我们的分析结果是一致的,所以我们的分析是正确的。

以上是关于Python内置函数super()的作用详解用最简单的例子把函数super()的作用和运行过程说清楚)的主要内容,如果未能解决你的问题,请参考以下文章

二十四Python中super()详解及应用场景举例

Python内置函数(63)——super

Python内置函数(30)——super

Python基础内置函数filter详解

Python基础内置函数filter详解

Python基础内置函数filter详解