探討 Python 的繼承衝突 - tsungjung411/python-study GitHub Wiki

繼承的衝突-範例一

class A:
    def print(self):
        print('call A.print()')
    # end-of-def
# end-of-class
        
class B:
    def print(self):
        print('call B.print()')
    # end-of-def
# end-of-class

class C1(A,B):
    pass
# end-of-class

class C2(B,A):
    pass
# end-of-class

c = C1()
c.print()
c = C2()
c.print()

print('\n呼叫順序:')
from pprint import pprint
pprint(C1.mro())
pprint(C2.mro())

執行結果:

call A.print()
call B.print()

呼叫順序:
[<class '__main__.C1'>,
 <class '__main__.A'>,
 <class '__main__.B'>,
 <class 'object'>]
[<class '__main__.C2'>,
 <class '__main__.B'>,
 <class '__main__.A'>,
 <class 'object'>]

說明:

  • 越靠近 class 名稱,優先權最高
  • class C1(A, B), A 距離 C1 最近,先呼叫 A 的 print 方法
  • class C2(B, A), B 距離 C2 最近,先呼叫 B 的 print 方法

繼承的衝突-範例二

class A:
    def print(self):
        print('call A.print()')
    # end-of-def
# end-of-class
        
class B(A):
    def print(self):
        print('call B1.print()')
    # end-of-def
# end-of-class

class C(A):
    pass
# end-of-class

class D1(B, C):
    pass
# end-of-class

class D2(C,B):
    pass
# end-of-class

d = D1()
d.print()
d = D2()
d.print()

print('\n呼叫順序:')
from pprint import pprint
pprint(D1.mro())
pprint(D2.mro())

執行結果:

call B1.print()
call B1.print()

呼叫順序:
[<class '__main__.D1'>,
 <class '__main__.B'>,
 <class '__main__.C'>,
 <class '__main__.A'>,
 <class 'object'>]
[<class '__main__.D2'>,
 <class '__main__.C'>,
 <class '__main__.B'>,
 <class '__main__.A'>,
 <class 'object'>]

Python 3: 印出 MRO 的幾個方法

class A: pass
class B(A): pass
class C(A): pass
class D1(B,C): pass
class D2(C,B): pass

import pprint
pprint.pprint(D1.mro())
pprint.pprint(D2.mro())

import inspect
print(inspect.getmro(D1))
print(inspect.getmro(D2))

執行結果:

[<class '__main__.D1'>,
 <class '__main__.B'>,
 <class '__main__.C'>,
 <class '__main__.A'>,
 <class 'object'>]
[<class '__main__.D2'>,
 <class '__main__.C'>,
 <class '__main__.B'>,
 <class '__main__.A'>,
 <class 'object'>]
(<class '__main__.D1'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
(<class '__main__.D2'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

一篇拓撲排序演算法的介紹,非常值得一看:

對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。簡單的說,由某個集合上的一個偏序得到該集合上的一個全序,這個操作稱之為拓撲排序。

其他參考資料

關鍵字

  • 方法解析順序, Method Resolution Order, MRO
  • 繼承, inherit, inheritance