Python进阶(七):super()函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37720172/article/details/78427641

很早就遇到了这个函数了,一直想写写这个函数的。但又觉得没必要,毕竟这个函数理解起来不难。直到我今天读到一篇文章:听说你会 Python ?有兴趣的可以去看看。


在文章里面提到了一个问题(代码我修改了一下下),就是使用了super()函数,读者们可以试着解解下面这道题:

class Init(object):
    def __init__(self, x):
        self.x = x

class Add(Init):
    def __init__(self, x):
        super(Add, self).__init__(x)
        self.x += 2

class Mul(Init):
    def __init__(self, x):
        super(Mul, self).__init__(x)
        self.x *= 5

class Sub(Mul, Add):
    def __init__(self, x):
        super(Sub, self).__init__(x)
        self.x -= 5

class Div(Sub):
    fsup = super(Sub)

    def __init__(self, x):
        self.fsup.__init__(x)
        self.x /= 5

test = Div(5)
print(test.x)

答案:7.0
如果这个你解出来了,那么恭喜,这篇文章不用看了。
如果不懂,没关系,跟着我魔鬼的步伐一起来看看这个super()到底是什么鬼东东。


一.继承

这个不用多说,不懂的猛戳这个连接:python的继承

给个例子理解一下:

class A(object):
    def __init__(self):
        print("Enter A")
        print("Exit A")

class B(A):
    def __init__(self):
        print("Enter B")
        A.__init__(self)
        print("Exit B")

b = B()

结果如图:
这里写图片描述
但是上面存在一个问题就是,假如我们修改了A类的名字,比如换成了C。这样我们就需要到子类B去修改A的名字了。上面的例子还好,子类B只需修改两次就OK了。但在实际开发中,项目比较大,有时一个子类要多次调用父类,这么一来,A的名字一旦被修改,那么要到子类B修改A的名字简直就是一个吃力不讨好的活。所以super()函数应运而生。


二.super()函数

上面例子说明了为什么要用super()。好,接下来开始使用super()函数了。

请看下面例子:

class A(object):
    def __init__(self):
        print("Enter A")
        print("Exit A")

class B(A):
    def __init__(self):
        print("Enter B")
        super(B, self).__init__()
        print("Exit B")

b = B()

结果和第一个例子一样。但是如果A的名字如过修改。只需在子类修改一次A的名字就好了。

来点有难度的:

class People(object):
     def __init__(self, name):
         self.name = name

     def introduce(self):
         print("My name is %s!" % self.name)

class Student(People):
    def __init__(self, name, id):
        super(Student, self).__init__(name)
        self.id = id

    def introduce(self):
        super(Student, self).introduce()
        print("My ID is %s" % self.id)

s = Student('Lifei', 123456)
s.introduce()

结果:
这里写图片描述

这个例子可以比较好的说明为什么要使用super()。如果我们不使用,那么在子类Student中修改People这个类名将要修改三次。如果子类大量调用父类的方法那么一旦需要修改,简直就是噩梦。上面两个例子我们只需修改第一行中的父类名字就可以了

三.深入了解super()

看到这里我们还是无法解决文章开头所提到的问题。
我们来看一个例子:

class A(object):
    def __init__(self):
        print("Enter A")
        print("Exit A")

class B(A):
    def __init__(self):
        print("Enter B")
        super(B, self).__init__()
        print("Exit B")

class C(A):
    def __init__(self):
        print("Enter C")
        super(C, self).__init__()
        print("Exit C")

class D(B, C):
    def __init__(self):
        print("Enter D")
        super(D, self).__init__()
        print("Exit D")

d = D()

结果:
这里写图片描述
这里有个问题就是为什么B类中初始化并不是A,而是跑去初始化C了呢!

凡事都有规范。当然类的继承也是一样的。只不过是通过方法解析顺序(Method Resolution Order, MRO)列表来实现的。这个就是生成了一个顺序列表,至于底层算法怎么样,我们不要去管他。只需知道他帮助我们将类的关系排好了队。
super(cls, type)传入cls类在表中的下一个类。
我们可以执行下以下代码

print(D.mro())

结果

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

所以类的初始化就是按照这个表中的顺序去进行的。当执行到B类时,程序会在B的mro()列表里面寻找到下一个类,然后进入。


**mro遵循的原则:
1.子类永远在父类前面
2.如果有多个父类,会根据它们在列表中的顺序被检查
3. 如果对下一个类存在两个合法的选择,选择第一个父类


当然,super()再调用的时候是可以简写为下面例子的,效果一模一样:

class A(object):
    def __init__(self):
        print("Enter A")
        print("Exit A")

class B(A):
    def __init__(self):
        print("Enter B")
        super().__init__()
        print("Exit B")

class C(A):
    def __init__(self):
        print("Enter C")
        super().__init__()
        print("Exit C")

class D(B, C):
    def __init__(self):
        print("Enter D")
        super().__init__()
        print("Exit D")

博文参考:
python super()
听说你会 Python ?

有问题探讨的请加QQ:1043601529

猜你喜欢

转载自blog.csdn.net/weixin_37720172/article/details/78427641
今日推荐