zoukankan      html  css  js  c++  java
  • 教你学会使用Python学习之类的继承super!

     

    看了网上许多关于super、mro、C3的介绍感觉没有一份很容易初学者理解的文档,直接看C3算法的话,比较难理解,也没必要,如果掌握一套规律的话,会轻松许多。我将网上这些博主的文章进行一个梳理总结,最后形成一套实用的关于super、mro、C3的理解介绍。

    1、super

    super()是一种将子类与父类联系起来的一种方法,子类通过继承父类,可以使用父类的方法和属性,也可以自己定义属于自己的方法和属性。super方法主要用在多继承中,在单继承时直接调用父类方法即可

    下面这个是SGD源码的一部分,根据这份源码,

    class SGD(Optimizer):    def __init__(self, params, lr=required, momentum=0, dampening=0,                 weight_decay=0, nesterov=False):        defaults = dict(lr=lr, momentum=momentum, dampening=dampening,                        weight_decay=weight_decay, nesterov=nesterov)        if nesterov and (momentum <= 0 or dampening != 0):            raise ValueError("Nesterov momentum requires a momentum and zero dampening")        super(SGD, self).__init__(params, defaults)    def __setstate__(self, state):        super(SGD, self).__setstate__(state)        for group in self.param_groups:            group.setdefault('nesterov', False)这是SGD类中的代码

    有2点需要补充说明:

    1、super联系父类的时候,需要调用父类的方法,包括所带的形参写完整,子类不够的形参需要额外加上

    2、super联系父类的时候,不只是可以调用__init__,而且还可以调用父类其他的方法

    3、python3可以写成super().__init__()这种写法了。

    4、类都默认继承object类

    另外,在super的使用过程中,还需要注意初始化对继承的影响:

    1、子类继承父类,但不执行__init__方法,那么会自动继承父类属性。

    2、子类继承父类,执行了__init__方法,且不调用super初始化父类构造函数,那么子类不会自动继承父类属性。

    3、子类继承父类,执行了__init__方法,且调用了super初始化了父类的构造函数,那么子类会继承父类属性。

    2、mro

    Python的MRO,方法解析顺序,即在调用方法时,会对当前类以及所有的基类进行一个搜索,以确定该方法之所在,而这个搜索的顺序就是MRO。然后python会按照这个顺序去执行类之间的调用问题。

    直接上例子

    class A1():
        def __init__(self):
            print('A1')
            super().__init__()
    class A2():
        def __init__(self):
            print('A2')
            super().__init__()
    class A3():
        def __init__(self):
            print('A3')
            super().__init__()
    class B1(A1, A2):
        def __init__(self):
            print('B1')
            super().__init__()
    class B2(A2):
        def __init__(self):
            print('B2')
            super().__init__()
    class B3(A2, A3):
        def __init__(self):
            print('B3')
            super().__init__()
    class C1(B1):
        def __init__(self):
            print('C1')
            super().__init__()
    class C2(B1, B2):
        def __init__(self):
            print('C2')
            super().__init__()
    class C3(B2, B3):
        def __init__(self):
            print('C3')
            super().__init__()
    class D(C1, C2, C3):
        def __init__(self):
            print('D')
            super().__init__()
    
    d = D()
    print(D.__mro__)

    输出如下:

    (<class '__main__.D'>, <class '__main__.C1'>, <class '__main__.C2'>, <class '__main__.B1'>, <class '__main__.A1'>, <class '__main__.C3'>, <class '__main__.B2'>, <class '__main__.B3'>, <class '__main__.A2'>, <class '__main__.A3'>, <class 'object'>)

    那么这个程序是按怎么个顺序依次去执行那些方法呢,就是按照MRO中的顺序。

    那么这个顺序如何自己手写出来呢?这就是C3算法,用于计算出MRO,得出执行顺序

    3、c3算法

    这个是网上转载一篇博主对于C3算法的介绍,有兴趣钻研的同学可以进去看看https://blog.csdn.net/fmblzf/article/details/52512145?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

    但是我在这里想告诉大家如何根据C3算法找出规律,从而自己写出顺序

    还是上手例子,根据上面这个图,我们可以列出下面这个表,这个表示网上一个博主做的,可以说做出这张表就是做出了答案,那这张表“实际取出的类”怎么推出来的呢?我拿过来提炼出一些比较直接的规律

    规律1:预查找父类按左边优先原则,比如第一行,当前类D的预查找父类选最左边的C1,而不是C2、C3。

    规律2:当“预查找父类是否还有其他子类?同时又是最底层查找类的父类或父父类、父父父...类”没有的时候,直接选取预查找父类作为答案。当这项有类的时候,若“最底层的未查找父类”还有,则优先选它,若没有了,则选取这项类作为答案。

    规律3:当预查找父类是object,只要最底层的未查找父类还有,就选这个最底层的未查找父类。若没有,则“预查找父类是否还有其他子类?同时又是最底层查找类的父类或父父类、父父父...类”有类的时候,就选这个类,没有的话,答案就是object

    另外,

    如何去画图:

    1、子类永远画在父类的下面,并用有向箭头指向父类

    2、遇到多继承则按代码中继承列表的顺序从左往右写。如果有多个子类继承了同一个父类,那么这个父类则放在它能够出现的所有位置中最左的位置。需遵循图里面的广度优先原则进行遍历(在广度优先原则的前提下又优先遍历左边的):

    练习:

    下面这个是网上的一份代码,看懂上面的规律以及如何画有向图之后,就可以顺利得出MRO的值了

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

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

    class D(A):
        def __init__(self):
            print('D')
            super().__init__()
            
    class E(B, C):
        def __init__(self):
            print('E')
            super().__init__()


    class F(C, D):
        def __init__(self):
            print('F')
            super().__init__()

    class G(E, F):
        def __init__(self):
            print('G')
            super().__init__()

    首先,画图

    然后列表

    当前类最底层未查找的父类预查找的父类预查找父类是否为object预查找父类是否有其他子类,同时又是最底层查找类的父类、父父类实际取出的类GE、FEnonoEEFBnonoBBFAno有,CFFnoCnonoCCnoAno有,DDDnoAnonoAAnoobjectyesnoobject

    答案:
    mro:GEBFC

    需要源代码的或者想了解更多的点击这里获取

    此文转载文,著作权归作者所有,如有侵权联系小编删除!

    原文地址:https://blog.csdn.net/MR_kdcon/article/details/108924836

  • 相关阅读:
    AndroidUI组件之ListView小技巧
    iframe属性參数
    Applet 数字签名技术全然攻略
    SoftReference
    递归算法浅谈
    VS2010 打包生成exe文件后 执行安装文件出现 TODO:&lt;文件说明&gt;已停止工作并已关闭
    创建新的Cocos2dx 3.0项目并解决一些编译问题
    ORACLE触发器具体解释
    SRM 624 D2L3: GameOfSegments, 博弈论,Sprague–Grundy theorem,Nimber
    cidaemon.exe进程cpu占用率高及关闭cidaemon.exe进程方法
  • 原文地址:https://www.cnblogs.com/wxys/p/13773351.html
Copyright © 2011-2022 走看看