欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python类的继承super相关原理解析

程序员文章站 2022-03-02 12:41:43
看了网上许多关于super、mro、c3的介绍感觉没有一份很容易初学者理解的文档,直接看c3算法的话,比较难理解,也没必要,如果掌握一套规律的话,会轻松许多。我将网上这些博主的文章进行一个梳理总结,最...

看了网上许多关于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__)

输出如下:

Python类的继承super相关原理解析

(<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中的顺序。

Python类的继承super相关原理解析

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

3、c3算法

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

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

Python类的继承super相关原理解析

规律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__()

首先,画图

Python类的继承super相关原理解析

然后列表

当前类最底层未查找的父类预查找的父类预查找父类是否为object预查找父类是否有其他子类,同时又是最底层查找类的父类、父父类实际取出的类ge、fenonoeefbnonobbfano有,cffnocnonoccnoano有,dddnoanonoaanoobjectyesnoobject

答案:

mro:gebfc

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。