Python新式類繼承的C3算法


在Python的新式類中,方法解析順序並非是廣度優先的算法,而是采用C3算法,只是在某些情況下,C3算法的結果恰巧符合廣度優先算法的結果。

可以通過代碼來驗證下:

class NewStyleClassA(object):
    var = 'New Style Class A'


class NewStyleClassB(NewStyleClassA):
    pass


class NewStyleClassC(NewStyleClassA):
    var = 'New Style Class C'


class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
    pass


if __name__ == '__main__':
    print(SubNewStyleClass.mro())
    print(SubNewStyleClass.var)

從第一段代碼的運行結果來看,與廣度優先的算法結果恰巧相同,但也只是恰巧相同,不等於就是廣度優先的算法。

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassC'>, <class '__main__.NewStyleClassA'>, <type 'object'>]
New Style Class C

通過對代碼進行修改可以證實:

將NewStyleClassC改為繼承自object

class NewStyleClassA(object):
    var = 'New Style Class A'


class NewStyleClassB(NewStyleClassA):
    pass


class NewStyleClassC(object):
    var = 'New Style Class C'


class SubNewStyleClass(NewStyleClassB, NewStyleClassC):
    pass


if __name__ == '__main__':
    print(SubNewStyleClass.mro())
    print(SubNewStyleClass.var)

運行代碼輸出結果

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class '__main__.NewStyleClassC'>, <type 'object'>]
New Style Class A

從代碼運行結果上看,並不符合廣度優先的原則。

 

關於C3算法,在Python官方文檔中是如此解釋的:

take the head of the first list, i.e L[B1][0]; if this head is not in the tail of any of the other lists, then add it to the linearization of C and remove it from the lists in the merge, otherwise look at the head of the next list and take it, if it is a good head. Then repeat the operation until all the class are removed or it is impossible to find good heads. In this case, it is impossible to construct the merge, Python 2.3 will refuse to create the class C and will raise an exception.

 

C3算法的本質就是Merge,不斷地把mro()函數返回的序列進行Merge,規則如下:

1. 如果第一個序列的第一個元素,是后續序列的第一個元素,或者不再后續序列中再次出現,則將這個元素合並到最終的方法解析順序序列中,並從當前操作的全部序列中刪除。

2. 如果不符合,則跳過此元素,查找下一個列表的第一個元素,重復1的判斷規則

 

使用第一段代碼逐步進行方法解析:

1.先打印NewStyleClassB和NewStyleClassC的mro(),得到他們的繼承順序序列

[<class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class 'object'>]
[<class '__main__.NewStyleClassC'>, <class 'object'>]

2.根據C3算法逐步對繼承順序進行解析:

mro(SubNewStyleClass)
    = [SubNewStyleClass] + merge(mro(NewStyleClassB), mro(NewStyleClassC), [NewStyleClassB, NewStyleClassC])
    # 根據第一步的打印結果,可以得出
    = [SubNewStyleClass] + merge([NewStyleClassB, NewStyleClassA, object],  [NewStyleClassC, NewStyleClassA, object], [NewStyleClassB, NewStyleClassC])
    # 判斷merge的當前序列第一個元素 NewStyleClassB, 在第三個序列中的第一個元素也存在,所以將其合並到最終序列並且刪除:
    = [SubNewStyleClass, NewStyleClassB] + merge([NewStyleClassA, object],  [NewStyleClassC, NewStyleClassA, object], [NewStyleClassC])
    # 判斷merge的當前序列第一個元素 NewStyleClassA,在第二個序列中存在,並且不為第二個序列的第一個元素,則跳過
    #  繼續判斷第二個序列中的第一個元素 NewStyleClassC,在第三個序列中存在,並且為第一個元素,所以將其合並到最終序列並且刪除:
    = [SubNewStyleClass, NewStyleClassB, NewStyleClassC] + merge([NewStyleClassA, object], [NewStyleClassA, object])
    # 目前第一個序列的第一個元素是NewStyleClassA,所以再次對NewStyleClassA進行判斷。
    # NewStyleClassA在第二個序列中存在,並且為第二個序列的第一個元素,所以將其合並到最終序列並且刪除:
    = [SubNewStyleClass, NewStyleClassB, NewStyleClassC, NewStyleClassA] + merge([object], [object])
    # 最終object,在第二個序列中出現,並且為第一個元素,所以將其合並到最終的序列並且刪除,得到最終的繼承順序:
    = [SubNewStyleClass, NewStyleClassB, NewStyleClassC, NewStyleClassA, object)

解析的結果和調用SubNewStyleClass.mro()方法打印出的結果是相同的:

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassC'>, <class '__main__.NewStyleClassA'>, <class 'object'>]

 

使用第二段代碼逐步進行方法解析:

1. 先打印NewStyleClassB和NewStyleClassC的mro(),得到他們的繼承順序序列

[<class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class 'object'>]
[<class '__main__.NewStyleClassC'>, <class 'object'>]

2. 根據C3算法逐步對繼承順序進行解析:

mro(SubNewStyleClass)
  = [SubNewStyleClass] + merge(mro(NewStyleClassB), mro(NewStyleClassC), [NewStyleClassB, NewStyleClassC])
  # 根據第一步的打印結果,可以得出
  = [SubNewStyleClass] + merge([NewStyleClassB, NewStyleClassA, object],  [NewStyleClassC, object], [NewStyleClassB, NewStyleClassC])
  # 判斷merge的當前序列第一個元素 NewStyleClassB, 在第三個序列中的第一個元素也存在,所以將其合並到最終序列並且刪除:
  = [SubNewStyleClass, NewStyleClassB] + merge([NewStyleClassA, object],  [NewStyleClassC, object], [NewStyleClassC])
  # 判斷merge的當前序列第一個元素 NewStyleClassA,在后續的序列中都不存在,所以將其合並到最終的序列並且刪除:
  = [SubNewStyleClass, NewStyleClassB, NewStyleClassA] + merge([object], [NewStyleClassC, object], [NewStyleClassC])
  # 判斷merge的當前序列第一個元素 object,在第二個序列中出現,並且不是第一個元素,則跳過
  # 跳過object后,繼續判斷下個序列的第一個元素,也就是第二個序列的第一個元素NewStyleClassC,在第三個序列中出現並且為第一個元素,所以將其合並到最終的序列並且刪除:
  = [SubNewStyleClass, NewStyleClassB, NewStyleClassA, NewStyleClassC] + merge([object], [object])
  # 再次判斷object,在第二個序列中出現,並且為第一個元素,所以將其合並到最終的序列並且刪除,得到最終的繼承順序:
  = [SubNewStyleClass, NewStyleClassB, NewStyleClassA, NewStyleClassC, object)

和調用SubNewStyleClass.mro()方法打印出的結果是相同的

[<class '__main__.SubNewStyleClass'>, <class '__main__.NewStyleClassB'>, <class '__main__.NewStyleClassA'>, <class '__main__.NewStyleClassC'>, <class 'object'>]

 


免責聲明!

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



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