詳解 Python super() 最簡單的解釋

首先提一下,經典類和新式類。在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]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章