最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python學習之MRO方法搜索順序

 更新時間:2021年09月07日 10:06:24   作者:小菠蘿測試筆記  
這篇文章主要介紹了Python MRO方法搜索順序,文中代碼和圖片解釋的非常詳細,可以很好的帶大家學習相關(guān)知識內(nèi)容,感興趣的小伙伴可以參考一下這篇文章

為什么會講 MRO?

  • 在講多繼承的時候,有講到, 當繼承的多個父類擁有同名屬性、方法,子類對象調(diào)用該屬性、方法時會調(diào)用哪個父類的屬性、方法呢?
  • 這就取決于 Python 的 MRO 了

什么是 MRO

  • MRO,method resolution order,方法搜索順序
  • 對于單繼承來說,MRO 很簡單,從當前類開始,逐個搜索它的父類有沒有對應的屬性、方法
  • 所以 MRO 更多用在多繼承時判斷方法、屬性的調(diào)用路徑
  • Python 中針對類提供了一個內(nèi)置屬性__mro__可以查看方法搜索順序

實際代碼

class A:
    def test(self):
        print("AAA-test")


class B:
    def test(self):
        print("BBB-test")


# 繼承了三個類,B、A、還有默認繼承的 object
class C(B, A):
    ...


# 通過類對象調(diào)用,不是實例對象!
print(C.__mro__)


# 輸出結(jié)果
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

  • 1.在搜索方法時,是按照__mro__的輸出結(jié)果從左往右的順序查找的
  • 2.如果在當前類(Class C)中找到方法,就直接執(zhí)行,不再搜索
  • 3.如果沒有找到,就查找下一個類中(Class B)是否有對應的方法,如果找到,就直接執(zhí)行,不再搜素
  • 4.如果找到最后一個類(Class object)都沒有找到方法,程序報錯

類圖

注意

其實 MRO 是涉及一個底層算法的,下面來詳細講解一下

MRO 算法

Python 發(fā)展到現(xiàn)在經(jīng)歷了三種算法

  • 舊式類 MRO 算法:從左往右,采用深度優(yōu)先搜索(DFS),從左往右的算法,稱為舊式類的 MRO
  • 新式類 MRO 算法:自 Python 2.2 版本開始,新式類在采用深度優(yōu)先搜索算法的基礎上,對其做了優(yōu)化
  • C3 算法:自 Python 2.3 版本,對新式類采用了 C3 算法;由于 Python 3.x 僅支持新式類,所以該版本只使用 C3 算法

什么是舊式類,新式類

Python學習之新式類和舊式類講解

想深入了解 C3 算法的可以看看官網(wǎng)

https://www.python.org/download/releases/2.3/mro/

舊式類 MRO 算法

需要在 python2 環(huán)境下運行這段代碼

實際代碼

# 舊式類算法
class A:
    def test(self):
        print("CommonA")


class B(A):
    pass


class C(A):
    def test(self):
        print("CommonC")


class D(B, C):
    pass


D().test()


# python2 下的運行結(jié)果
CommonA

類圖

分析

  • 通過類圖可以看到,此程序中的 4 個類是一個“菱形”繼承的關(guān)系
  • 當使用 D 類實例對象訪問 test() 方法時,根據(jù)深度優(yōu)先算法,搜索順序為D->B->A->C->A
  • 因此,舊式類 MRO 算法最先搜索得到 test() 方法是在 A 類里面,所以最終輸出結(jié)果為 CommonA

新式類 MRO 算法

  • 為解決舊式類 MRO 算法存在的問題,Python 2.2 版本推出了新的計算新式類 MRO 的方法
  • 它仍然采用從左至右的深度優(yōu)先遍歷,但是如果遍歷中出現(xiàn)重復的類,只保留最后一個

以上面的代碼栗子來講

  • 深度優(yōu)先遍歷,搜索順序為D->B->A->C->A
  • 因為順序中有 2 個 A,因此只保留最后一個
  • 最終搜索順序為D->B->C->A

新式 MRO 算法的問題

雖然解決了舊式 MRO 算法的問題,但可能會違反單調(diào)性原則

什么是單調(diào)性原則?

在子類存在多繼承時,子類不能改變父類的 MRO 搜索順序,否則會導致程序發(fā)生異常

實際代碼

class X(object):
    pass


class Y(object):
    pass


class A(X, Y):
    pass


class B(Y, X):
    pass


class C(A, B):
    pass

深度優(yōu)先遍歷后的搜索順序為:C->A->X->object->Y->object->B->Y->object->X->object

相同取后者的搜索順序為:C->A->B->Y->X->object

分析不同類的 MRO

  • A:A->X->Y->object
  • B:A->Y->X->object
  • C:C->A->B->X->Y->object

很明顯,B、C 中間的 X、Y 順序是相反的,就是說 B 被繼承時,它的搜索順序會被改變,違反了單調(diào)性

在 python2 中運行這段代碼的報錯

在 python3 中運行這段代碼的報錯

C3 MRO 算法

  • 為解決前面兩個算法的問題,Python 2.3 采用了 C3 方法來確定方法搜索順序
  • 多數(shù)情況下,如果別人提到 Python 中的 MRO,指的都是 C3 算法

將上面第一個栗子的代碼放到 python3 中運行

class A:
    def test(self):
        print("CommonA")


class B(A):
    pass


class C(A):
    def test(self):
        print("CommonC")


class D(B, C):
    pass


D().test()


# 輸出結(jié)果
CommonC

簡單了解下 C3 算法

以上面代碼為栗子,C3 會把各個類的 MRO 等價為以下等式

  • A:L[A] = merge(A , object)
  • B:L[B] = B + merge(L[A] , A)
  • C:L[C] = C + merge(L[A] , A)
  • D:L[D] = D + merge(L[B] , L[C] , B , C)

了解一下:頭、尾

以 A 類為栗,merge() 包含的 A 成為 L[A] 的頭,剩余元素(這里只有 object)稱為尾

merge 的運算方式

  • 1.將merge 第一個列表的頭元素(如 L[A] 的頭),記作 H
  • 2.如果 H 出現(xiàn)在 merge 其他列表的頭部,則將其輸出,并將其從所有列表中刪除
  • 3.如果 H 只出現(xiàn)一次,那么也將其輸出,并將其從所有列表中刪除
  • 4.如果 H 出現(xiàn)在 merge 其他列表的非頭部,則取下一個列表的頭元素記作 H,然后回到步驟二
  • 5.最后回到步驟一,重復以上步驟

重復以上步驟直到列表為空,則算法結(jié)束;如果不能再找出可以輸出的元素,則拋出異常

簡單類 MRO 的計算栗子

class B(object): pass

print(B.__mro__)


(<class '__main__.B'>, <class 'object'>)
  • MRO 計算方式
L[B] = L[B(object)]
     = B + merge(L[object])
     = B + L[object]
     = B object

單繼承MRO 的計算栗子

# 計算 MRO
class B(object): pass

class C(B): pass

print(C.__mro__)


(<class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
  • MRO 計算方式
L[C] = C + merge(L[B])
     = C + L[B]
     = C B object

多繼承MRO 的計算栗子

O = object

class F(O): pass

class E(O): pass

class D(O): pass

class C(D, F): pass

class B(D, E): pass

class A(B, C): pass


print(C.__mro__)
print(B.__mro__)
print(A.__mro__)


# 輸出結(jié)果
(<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
(<class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)

  • O 類、object 類 MRO 計算
L[O] = O = object
  • D、E、F 類 MRO 計算
L[D] = D + merge(L[O])
        = D O
  • C 類 MRO 計算
L[C] = L[C(D, F)]
     = C + merge(L[D], L[F], DF)
     # 從前面可知 L[D] 和 L[F] 的結(jié)果
     = C +  merge(DO, FO, DF)
     # 因為 D 是順序第一個并且在幾個包含 D 的 list 中是 head,
     # 所以這一次取 D 同時從列表中刪除 D
     = C + D + merge(O, FO, F)
     # 因為 O 雖然是順序第一個但在其他 list (FO)中是在尾部, 跳過
     # 改為檢查第二個list FO
     # F 是第二個 list 和其他 list 的 head
     # 取 F 同時從列表中刪除 F
     = C + D + F + merge(O)
     = C D F O
  • B 類 MRO 計算
L[B] = L[B(D, E)]
     = B + merge(L[D], L[E], DE)
     = B + merge(DO, EO, DE)
     = B + D + merge(O, EO, E)
     = B + D + E + merge(O)
     = B D E O
  • A 類 MRO 計算
L[A] = L[A(B,C)]
        = A + merge(L[B], L[C], BC)
        = A + merge( BDEO, CDFO, BC )
        = A + B + merge( DEO, CDFO, C )
        # D 在其他列表 CDFO 不是 head,所以跳過到下一個列表的 頭元素 C
        = A + B + C + merge( DEO, DFO )
        = A + B + C + D + merge( EO, FO )
        = A + B + C + D + E + merge( O, FO )
        = A + B + C + D + E + F + merge( O )
        = A B C D E F O

多繼承MRO 的計算栗子二

O = object

class F(O): pass

class E(O): pass

class D(O): pass

class C(D, F): pass

class B(E, D): pass

class A(B, C): pass


print(C.__mro__)
print(B.__mro__)
print(A.__mro__)


# 輸出結(jié)果
(<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
(<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)

  • O 類、object 類 MRO 計算
L[O] = O = object
  • D、E、F 類 MRO 計算
L[D] = D + merge(L[O])
        = D O
  • C 類 MRO 計算
L[C] = L[C(D, F)]
        = C + merge(L[D], L[F], DF)
        = C + merge(DO, FO, DF)
        = C + D + merge(O, FO, F)
        = C + D + F + merge(O)
        = C D F O
  • B 類 MRO 計算
L[B] = L[B(E, D)]
       = B + merge(L[E], L[D], ED)
       = B + merge(EO, DO, ED)
       = B + E + merge(O, DO, D)
       = B + E + D + merge(O)
       = B E D O
  • A 類 MRO 計算
L[A]  = L[A(B, C)]
        = A + merge(L[B], L[C], BC)
        = A + merge(BEDO, CDFO, BC)
        = A + B + merge(EDO, CDFO, C)
        = A + B + E + merge(DO,CDFO, C)
        = A + B + E + C + merge(O,DFO)
        = A + B + E + C + D + merge(O, FO)
        = A + B + E + C + D + F + merge(O)
        = A B E C D F O

到此這篇關(guān)于Python學習之MRO方法搜索順序的文章就介紹到這了,更多相關(guān)Python MRO方法搜索順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • pyqt5 實現(xiàn)多窗口跳轉(zhuǎn)的方法

    pyqt5 實現(xiàn)多窗口跳轉(zhuǎn)的方法

    今天小編就為大家分享一篇pyqt5 實現(xiàn)多窗口跳轉(zhuǎn)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Python3與redis交互,保存的是字符串,取出來是bytes類型問題

    Python3與redis交互,保存的是字符串,取出來是bytes類型問題

    這篇文章主要介紹了Python3與redis交互,保存的是字符串,取出來是bytes類型問題,具有很好的參考價值,希望對大家有所幫助,
    2023-09-09
  • Python與R語言的簡要對比

    Python與R語言的簡要對比

    這篇文章主要介紹了Python與R語言的簡要對比,小編覺得還挺不錯的,這里分享給大家,需要的朋友可以了解下。
    2017-11-11
  • python datetime處理時間小結(jié)

    python datetime處理時間小結(jié)

    這篇文章主要介紹了python datetime處理時間小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • 舉例介紹Python中的25個隱藏特性

    舉例介紹Python中的25個隱藏特性

    這篇文章主要介紹了一些Python中的隱藏特性,從stackoverflow的人氣問題回答中整理而來,主要以代碼實際解釋說明,需要的朋友可以參考下
    2015-03-03
  • Python結(jié)合Redis開發(fā)一個消息訂閱系統(tǒng)

    Python結(jié)合Redis開發(fā)一個消息訂閱系統(tǒng)

    消息訂閱是一種常見的通信模式,用于實現(xiàn)系統(tǒng)之間的解耦和異步通信,本文將詳細介紹如何使用Python實現(xiàn)一個高效與可靠的消息訂閱系統(tǒng),有需要的可以了解下
    2025-03-03
  • 詳解用Python把PDF轉(zhuǎn)為Word方法總結(jié)

    詳解用Python把PDF轉(zhuǎn)為Word方法總結(jié)

    這篇文章主要介紹了詳解用Python把PDF轉(zhuǎn)為Word方法總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 基于python實現(xiàn)地址和經(jīng)緯度轉(zhuǎn)換

    基于python實現(xiàn)地址和經(jīng)緯度轉(zhuǎn)換

    這篇文章主要介紹了基于python實現(xiàn)地址和經(jīng)緯度轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • pymongo實現(xiàn)多結(jié)果進行多列排序的方法

    pymongo實現(xiàn)多結(jié)果進行多列排序的方法

    這篇文章主要介紹了pymongo實現(xiàn)多結(jié)果進行多列排序的方法,涉及Python排序的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • 詳解OpenCV圖像的概念和基本操作

    詳解OpenCV圖像的概念和基本操作

    opencv最主要的的功能是用于圖像處理,所以圖像的概念貫穿了整個opencv,與其相關(guān)的核心類就是Mat。這篇文章主要介紹了OpenCV圖像的概念和基本操作,需要的朋友可以參考下
    2021-10-10

最新評論

长沙县| 兰西县| 道孚县| 繁昌县| 贵定县| 仁化县| 定陶县| 松阳县| 龙江县| 大关县| 莱州市| 平利县| 宁陵县| 杂多县| 通江县| 二连浩特市| 延寿县| 玉林市| 视频| 肥城市| 临江市| 信丰县| 汉源县| 深水埗区| 金塔县| 高安市| 美姑县| 连山| 齐河县| 资中县| 青神县| 灌阳县| 噶尔县| 新乐市| 稷山县| 逊克县| 宜君县| 资源县| 海门市| 广德县| 霍山县|