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

来源:互联网 发布:中国汽车制造业 数据 编辑:程序博客网 时间:2024/05/29 08:16

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


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

class Init(object):    def __init__(self, x):        self.x = xclass Add(Init):    def __init__(self, x):        super(Add, self).__init__(x)        self.x += 2class Mul(Init):    def __init__(self, x):        super(Mul, self).__init__(x)        self.x *= 5class Sub(Mul, Add):    def __init__(self, x):        super(Sub, self).__init__(x)        self.x -= 5class Div(Sub):    fsup = super(Sub)    def __init__(self, x):        self.fsup.__init__(x)        self.x /= 5test = 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

原创粉丝点击