菱形繼承問題


一、類的分類

1.1 新式類

  • 繼承了object的類以及該類的子類,都是新式類

  • Python3中所有的類都是新式類

1.2 經典類

  • 沒有繼承object的類以及該類的子類,都是經典類

  • 只有Python2中才有經典類

二、菱形繼承問題

92-菱形繼承問題-繼承關機.jpg?x-oss-process=style/watermark

在Java和C#中子類只能繼承一個父類,而Python中子類可以同時繼承多個父類,如A(B,C,D)

如果繼承關系為非菱形結構,則會按照先找B這一條分支,然后再找C這一條分支,最后找D這一條分支的順序直到找到我們想要的屬性

如果繼承關系為菱形結構,即子類的父類最后繼承了同一個類,那么屬性的查找方式有兩種:

  • 經典類下:深度優先

  • 廣度優先:廣度優先

  • 經典類:一條路走到黑,深度優先

92-菱形繼承問題-經典類.png?x-oss-process=style/watermark

  • 新式類:不找多各類最后繼承的同一個類,直接去找下一個父類,廣度優先

92-菱形繼承問題-新式類.png?x-oss-process=style/watermark

class G(object):
    # def test(self):
    #     print('from G')
    pass


print(G.__bases__)


class E(G):
    # def test(self):
    #     print('from E')
    pass


class B(E):
    # def test(self):
    #     print('from B')
    pass


class F(G):
    # def test(self):
    #     print('from F')
    pass


class C(F):
    # def test(self):
    #     print('from C')
    pass


class D(G):
    # def test(self):
    #     print('from D')
    pass


class A(B, C, D):
    def test(self):
        print('from A')


obj = A()
(<class 'object'>,)
obj.test()  # A->B->E-C-F-D->G-object
from A

三、C3算法與mro()方法介紹

92-菱形繼承問題-飛船原理.jpg?x-oss-process=style/watermark

python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,如:

print(A.mro())  # A.__mro__
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
for i in A.mro():
    print(i)
<class '__main__.A'>
<class '__main__.B'>
<class '__main__.E'>
<class '__main__.C'>
<class '__main__.F'>
<class '__main__.D'>
<class '__main__.G'>
<class 'object'>

為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。

而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條准則:

  1. 子類會先於父類被檢查
  2. 多個父類會根據它們在列表中的順序被檢查
  3. 如果對下一個類存在兩個合法的選擇,選擇第一個父類


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM