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

C3 線(xiàn)性化算法與 MRO之Python中的多繼承

 更新時(shí)間:2021年10月04日 10:37:43   作者:A Coder is a Poet  
Python 中的方法解析順序(Method Resolution Order, MRO)定義了多繼承存在時(shí) Python 解釋器查找函數(shù)解析的正確方式。這篇文章給大家介紹了Python中的多繼承,感興趣的朋友一起看看吧

Python 中的方法解析順序(Method Resolution Order, MRO)定義了多繼承存在時(shí) Python 解釋器查找函數(shù)解析的正確方式。當(dāng) Python 版本從 2.2 發(fā)展到 2.3 再到現(xiàn)在的 Python 3,MRO算法也隨之發(fā)生了相應(yīng)的變化。這種變化在很多時(shí)候影響了我們使用不同版本 Python 編程的過(guò)程。

什么是 MRO

MRO 全稱(chēng)方法解析順序(Method Resolution Order)。它定義了 Python 中多繼承存在的情況下,解釋器查找函數(shù)解析的具體順序。什么是函數(shù)解析順序?我們首先用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明。請(qǐng)仔細(xì)看下面代碼:

class A():
    def who_am_i(self):
        print("I am A")
        
class B(A):
    pass
        
class C(A):
    def who_am_i(self):
        print("I am C")

class D(B,C):
    pass
    
d = D()

如果我問(wèn)在 Python 2 中使用 D 的實(shí)例調(diào)用 d.who_am_i(),究竟執(zhí)行的是 A 中的 who_am_i() 還是 C 中的 who_am_i(),我想百分之九十以上的人都會(huì)不假思索地回答:肯定是 C 中的 who_am_i(),因?yàn)?C 是 D 的直接父類(lèi)。然而,如果你把代碼用 Python 2 運(yùn)行一下就可以看到 d.who_am_i() 打印的是 I am A。

是不是覺(jué)得很混亂很奇怪?感到奇怪就對(duì)了!?。?/p>

這個(gè)例子充分展示了 MRO 的作用:決定基類(lèi)中的函數(shù)到底應(yīng)該以什么樣的順序調(diào)用父類(lèi)中的函數(shù)??梢悦鞔_地說(shuō),Python 發(fā)展到現(xiàn)在,MRO 算法已經(jīng)不是一個(gè)憑借著執(zhí)行結(jié)果就能猜出來(lái)的算法了。如果沒(méi)有深入到 MRO 算法的細(xì)節(jié),稍微復(fù)雜一點(diǎn)的繼承關(guān)系和方法調(diào)用都能徹底繞暈?zāi)恪?/p>

New-style Class vs. Old-style Class

在介紹不同版本的 MRO 算法之前,我們有必要簡(jiǎn)單地回顧一下 Python 中類(lèi)定義方式的發(fā)展歷史。盡管在 Python 3 中已經(jīng)廢除了老式的類(lèi)定義方式和 MRO 算法,但對(duì)于仍然廣泛使用的 Python 2 來(lái)說(shuō),不同的類(lèi)定義方式與 MRO 算法之間具有緊密的聯(lián)系。了解這一點(diǎn)將幫助我們從 Python 2 向 Python 3 遷移時(shí)不會(huì)出現(xiàn)莫名其妙的錯(cuò)誤。

在 Python 2.1 及以前,我們定義一個(gè)類(lèi)的時(shí)候往往是這個(gè)樣子(我們把這種類(lèi)稱(chēng)為 old-style class):

class A:
    def __init__(self):
        pass

Python 2.2 引入了新的模型對(duì)象(new-style class),其建議新的類(lèi)型通過(guò)如下方式定義:

class A(object):
    def __init__(self):
        pass

注意后一種定義方式顯示注明類(lèi) A 繼承自 object。Python 2.3 及后續(xù)版本為了保持向下兼容,同時(shí)提供以上兩種類(lèi)定義用以區(qū)分 old-style class 和 new-style class。Python 3 則完全廢棄了 old-style class 的概念,不論你通過(guò)以上哪種方式書(shū)寫(xiě)代碼,Python 3 都將明確認(rèn)為類(lèi) A 繼承自 object。這里我們只是引入 old-style 和 new-style 的概念,如果你對(duì)他們的區(qū)別感興趣,可以自行看 stackoverflow 上有關(guān)該問(wèn)題的解釋。

理解 old-style class 的 MRO

我們使用前文中的類(lèi)繼承關(guān)系來(lái)介紹 Python 2 中針對(duì) old-style class 的 MRO 算法。如果你在前面執(zhí)行過(guò)那段代碼,你可以看到調(diào)用 d.who_am_i() 打印的應(yīng)該是 I am A。為什么 Python 2 的解釋器在確定 D 中的函數(shù)調(diào)用時(shí)要先搜索 A 而不是先搜索 D 的直接父類(lèi) C 呢?

這是由于 Python 2 對(duì)于 old-style class 使用了非常簡(jiǎn)單的基于深度優(yōu)先遍歷的 MRO 算法(關(guān)于深度優(yōu)先遍歷,我想大家肯定都不陌生)。當(dāng)一個(gè)類(lèi)繼承自多個(gè)類(lèi)時(shí),Python 2 按照從左到右的順序深度遍歷類(lèi)的繼承圖,從而確定類(lèi)中函數(shù)的調(diào)用順序。這個(gè)過(guò)程具體如下:

  • 檢查當(dāng)前的類(lèi)里面是否有該函數(shù),如果有則直接調(diào)用。
  • 檢查當(dāng)前類(lèi)的第一個(gè)父類(lèi)里面是否有該函數(shù),如果沒(méi)有則檢查父類(lèi)的第一個(gè)父類(lèi)是否有該函數(shù),以此遞歸深度遍歷。
  • 如果沒(méi)有則回溯一層,檢查下一個(gè)父類(lèi)里面是否有該函數(shù)并按照 2 中的方式遞歸。

上面的過(guò)程與標(biāo)準(zhǔn)的深度優(yōu)先遍歷只有一點(diǎn)細(xì)微的差別:步驟 2 總是按照繼承列表中類(lèi)的先后順序來(lái)選擇分支的遍歷順序。具體來(lái)說(shuō),類(lèi) D 的繼承列表中類(lèi)順序?yàn)?B, C,因此,類(lèi) D 按照先遍歷 B 分支再遍歷 C 分支的順序來(lái)確定 MRO。

我們繼續(xù)用第一個(gè)例子中的函數(shù)繼承圖來(lái)說(shuō)明這個(gè)過(guò)程:

按照上述深度遞歸的方式,函數(shù) d.who_am_i() 調(diào)用的搜索順序是 D, B, A, C, A。由于一個(gè)類(lèi)不能兩次出現(xiàn),因此在搜索路徑中去除掉重復(fù)出現(xiàn)的 A,得到最終的方法解析順序是 D, B, A, C。這樣一來(lái)你就明白了為什么 d.who_am_i() 打印的是 I am A 了。

在 Python 2 中,我們可以通過(guò)如下方式來(lái)查看 old-style class 的 MRO:

>>> import inspect
>>> inspect.getmro(D)

理解 new-style class 的 MRO

從上面的結(jié)果可以看到,使用深度優(yōu)先遍歷的查找算法并不合理。因此,Python 3 以及 Python 2 針對(duì) new-style class 采用了新的 MRO 算法。如果你使用 Python 3 重新運(yùn)行一遍上述腳本,你就可以看到函數(shù) d.who_am_i() 的打印結(jié)果是 I am C

>>> d.who_am_i()
I am C
>>> D.__mro__
(<class 'test.D'>, <class 'test.B'>, <class 'test.C'>, <class 'test.A'>, <class 'object'>)

新算法與基于深度遍歷的算法類(lèi)似,但是不同在于新算法會(huì)對(duì)深度優(yōu)先遍歷得到的搜索路徑進(jìn)行額外的檢查。其從左到右掃描得到的搜索路徑,對(duì)于每一個(gè)節(jié)點(diǎn)解釋器都會(huì)判斷該節(jié)點(diǎn)是不是好的節(jié)點(diǎn)。如果不是好的節(jié)點(diǎn),那么將其從當(dāng)前的搜索路徑中移除。

那么問(wèn)題在于,什么是一個(gè)好的節(jié)點(diǎn)?我們說(shuō) N 是一個(gè)好的節(jié)點(diǎn)當(dāng)且僅當(dāng)搜索路徑中 N 之后的節(jié)點(diǎn)都不繼承自 N。我們還以上述的類(lèi)繼承圖為例,按照深度優(yōu)先遍歷得到類(lèi) D 中函數(shù)的搜索路徑 D, B, A, C, A。之后 Python 解釋器從左向右檢查時(shí)發(fā)現(xiàn)第三個(gè)節(jié)點(diǎn) A 不是一個(gè)好的節(jié)點(diǎn),因?yàn)?A 之后的節(jié)點(diǎn) C 繼承自 A。因此其將 A 從搜索路徑中移除,然后得到最后的調(diào)用順序 D, B, C, A。

采用上述算法,D 中的函數(shù)調(diào)用將優(yōu)先查找其直接父類(lèi) B 和 C 中的相應(yīng)函數(shù)。

C3線(xiàn)性化算法

上一小結(jié)我們從直觀(guān)上概述了針對(duì) new-style class 的 MRO 算法過(guò)程。事實(shí)上這個(gè)算法有一個(gè)明確的名字 C3 linearization。下面我們給出其形式化的計(jì)算過(guò)程。

上面的過(guò)程看起來(lái)好像很復(fù)雜,我們用一個(gè)例子來(lái)具體執(zhí)行一下,你就會(huì)覺(jué)得其實(shí)還是挺簡(jiǎn)單的。假設(shè)我們有如下的一個(gè)類(lèi)繼承關(guān)系:

class X():
    def who_am_i(self):
        print("I am a X")
        
class Y():
    def who_am_i(self):
        print("I am a Y")
        
class A(X, Y):
    def who_am_i(self):
        print("I am a A")
        
class B(Y, X):
     def who_am_i(self):
         print("I am a B")
         
class F(A, B):
    def who_am_i(self):
        print("I am a F")

Traceback (most recent call last):
  File "test.py", line 17, in <module>
    class F(A, B):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y

參考文獻(xiàn) Python Tutorial: Understanding Python MRO - Class search path The Python 2.3 Method Resolution Order C3 linearization

到此這篇關(guān)于C3 線(xiàn)性化算法與 MRO之Python中的多繼承的文章就介紹到這了,更多相關(guān)Python多繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Pycharm打印大數(shù)據(jù)文件顯示不全的解決方法

    Pycharm打印大數(shù)據(jù)文件顯示不全的解決方法

    這篇文章主要介紹了Pycharm打印大數(shù)據(jù)文件顯示不全的解決方法,昨晚寫(xiě)了個(gè)小爬蟲(chóng),簡(jiǎn)單分析下發(fā)現(xiàn)可以修改請(qǐng)求的url,直接獲取所有目標(biāo)的數(shù)據(jù),想先打印在控制臺(tái)看看,發(fā)現(xiàn)打印的數(shù)據(jù)不全,所以本文記錄了一下解決方法,需要的朋友可以參考下
    2024-03-03
  • Python中第三方庫(kù)Requests庫(kù)的高級(jí)用法詳解

    Python中第三方庫(kù)Requests庫(kù)的高級(jí)用法詳解

    雖然Python的標(biāo)準(zhǔn)庫(kù)中urllib2模塊已經(jīng)包含了平常我們使用的大多數(shù)功能,但是它的API使用起來(lái)讓人實(shí)在感覺(jué)不好。它已經(jīng)不適合現(xiàn)在的時(shí)代,不適合現(xiàn)代的互聯(lián)網(wǎng)了。而Requests的誕生讓我們有了更好的選擇。本文就介紹了Python中第三方庫(kù)Requests庫(kù)的高級(jí)用法。
    2017-03-03
  • 如何利用Python給自己的頭像加一個(gè)小國(guó)旗(小月餅)

    如何利用Python給自己的頭像加一個(gè)小國(guó)旗(小月餅)

    這篇文章主要給大家介紹了關(guān)于如何利用Python給自己的頭像加一個(gè)小國(guó)旗(小月餅)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • python+mysql實(shí)現(xiàn)個(gè)人論文管理系統(tǒng)

    python+mysql實(shí)現(xiàn)個(gè)人論文管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了python+mysql實(shí)現(xiàn)個(gè)人論文管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • python繪制ROC曲線(xiàn)的示例代碼

    python繪制ROC曲線(xiàn)的示例代碼

    本文主要介紹了python繪制ROC曲線(xiàn)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • PyQt5入門(mén)之基于QListWidget版本實(shí)現(xiàn)圖片縮略圖列表功能

    PyQt5入門(mén)之基于QListWidget版本實(shí)現(xiàn)圖片縮略圖列表功能

    這篇文章主要介紹了PyQt5入門(mén)之基于QListWidget版本實(shí)現(xiàn)圖片縮略圖列表功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • python中join與os.path.join()函數(shù)實(shí)例詳解

    python中join與os.path.join()函數(shù)實(shí)例詳解

    os.path.join()函數(shù)用于路徑拼接文件路徑,下面這篇文章主要給大家介紹了關(guān)于python中join與os.path.join()函數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03
  • 使用Python編寫(xiě)一個(gè)桌面便簽應(yīng)用

    使用Python編寫(xiě)一個(gè)桌面便簽應(yīng)用

    ChatGPT的編程能力也不差,本文將一步一步提出要求,讓ChatGPT根據(jù)我們的要求,編寫(xiě)出一個(gè)可用的,可打包運(yùn)行的桌面便簽,感興趣的可以了解一下
    2023-06-06
  • pycharm實(shí)現(xiàn)設(shè)置自動(dòng)的參數(shù)注釋標(biāo)識(shí)

    pycharm實(shí)現(xiàn)設(shè)置自動(dòng)的參數(shù)注釋標(biāo)識(shí)

    這篇文章主要介紹了pycharm實(shí)現(xiàn)設(shè)置自動(dòng)的參數(shù)注釋標(biāo)識(shí),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 詳解python中l(wèi)ist的使用

    詳解python中l(wèi)ist的使用

    這篇文章主要介紹了python中l(wèi)ist的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論

固镇县| 安多县| 晋中市| 隆回县| 昌平区| 郁南县| 杨浦区| 浦北县| 衡东县| 伊吾县| 五大连池市| 高青县| 怀宁县| 井冈山市| 光山县| 长治市| 孟连| 赣榆县| 乌拉特中旗| 大荔县| 肥西县| 潼关县| 泌阳县| 赤水市| 都安| 和林格尔县| 花莲县| 盘锦市| 茂名市| 麻城市| 镇原县| 上虞市| 麟游县| 大同市| 丰顺县| 静宁县| 凤庆县| 兴义市| 岐山县| 富蕴县| 铁岭市|