详解 Python super() 最简单的解释

时间:2020-6-29 作者:admin

首先提一下,经典类和新式类。在Python2中,如果定义类的方式是 class MyClass:   那么该类叫做经典类,如果定义类的方式为class MyClass(object): 那么该类为新式类。在Python3中,上面两种方式定义出来的类都叫新式类。本文是基于新式类来进行讲解的。

正文:

Python 中的 super() 是用于调用父类(或父类的父类…)方法的 函数,主要用于多继承,单继承问题不大。下面是一个多继承实例,继承关系为菱形继承, 仔细观察下面三个实例:

#coding=utf-8
#实例一:
class A(object):
    def __init__(self):
        print("class ---- A ----")

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

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

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

d = D()
'''
#输出结果:
class ---- D ----
class ---- B ----
class ---- C ----
class ---- A ----
'''
#coding=utf-8
#实例二: 更改一下类D的super函数:
class D(B, C):
    def __init__(self):
        print("class ---- D ----")
        super(B, self).__init__()

d = D()
'''
#输出结果:
class ---- D ----
class ---- C ----
class ---- A ----
'''
# 实例三: 再更改一下类D的super函数:
class D(B, C):
    def __init__(self):
        print("class ---- D ----")
        super(C, self).__init__()

d = D()
'''
# 输出结果:
class ---- D ----
class ---- A ----
'''

如果你认为 super()函数就是 调用父类的方法,那你可能想不通后面两个实例。原因是,super 和父类没有实质性的关联。如果想要搞懂super()函数的运行原理,那一定要先搞懂 __mro__ 属性,  mro 是Method Resolution Order,中文方法解析顺序。单继承中super()函数使用比较简单的原因 也是因为 mro 比较简单,多继承的mro就稍微复杂了,总之 mro的目的就是 按照一定顺序,保证父类的函数只调用一次

我们来先打印一下 它的属性值,再次修改类D的super函数:

class D(B, C):
    def __init__(self):
        print(D.__mro__)
        print("class ---- D ----")
        super(D, self).__init__()

d = D()

'''
#输出结果:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
class ---- D ----
class ---- B ----
class ---- C ----
class ---- A ----
'''

从打印结果可以看出,mro 是一个元组,类D的mro顺序是  D -> B -> C -> A -> object。也就是说,如果在类D中 使用super()函数时给传入的第一个参数是D,那么super函数就会在 mro 里从D的上一级开始查找,它的上一级是B, 那么super(D, self).__init__() 就调用B的__init__()函数,B的__init__()函数里又调用了B的super()函数,super(B, self).__init__(), 那就再从B的上一级开始查找,B的上一级是C, 以此类推,然后是A,最后是object。于是实例一也就解释清楚了。

实例二中 类D的super()方法第一个参数传入的是 B ,那么根据mro顺序开始查找,B的上一级是C,C的上一级是A,所以实例二的打印顺序是 D – > C -> A

实例三也就不难解释了。

最后再讲一下 super()函数的参数,该函数需要两个参数,第一个是类名,第二个一般都是self,但偶尔也有cls的情况,在:Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx, 比如:

class D(B, C):
    def __init__(self):
        print(D.__mro__)
        print("class ---- D ----")
        super().__init__()
d = D()
'''
#输出结果:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
class ---- D ----
class ---- B ----
class ---- C ----
class ---- A ----
'''

再回到文章的开始,谈一下经典类和新式类:

经典类的MRO方法是采用 从左至右的深度优先遍历 的算法,重复留前者

按照深度遍历,其顺序为 [D, B, A, object, C, A, object],重复者只保留前面一个,因此变为 [D, B, A, object, C]

新式类的MRO方法是采用 从左至右的深度优先遍历 的算法,重复留后者

按照深度遍历,其顺序为 [D, B, A, object, C, A, object],重复者只保留后面一个,因此变为 [D, B, C, A, object]

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。