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

一文講解python中的繼承沖突及繼承順序

 更新時(shí)間:2024年03月31日 10:54:58   作者:宇航員寫(xiě)代碼  
python支持多繼承,如果子類(lèi)沒(méi)有重寫(xiě)方法,則默認(rèn)會(huì)調(diào)用父類(lèi)的方法,本文主要介紹了一文講解python中的繼承沖突及繼承順序,具有一定的參考價(jià)值,感興趣的可以了解一下

簡(jiǎn)單的菱形繼承

設(shè)計(jì)類(lèi)如下

設(shè)計(jì)代碼:

class Animal(object):
    def __init__(self, age: int = None, gender: int = None) -> None:
        print("Call the constructor of Animal.")
        self.m_age = age
        self.m_gender = gender
        self.m_name = "Animal"
        print("Ends the call to Animal's constructer.")
        pass

    def eat(self):
        print("Animal is eating")

    def sleep(self):
        print("Animal is sleeping")


class Tiger(Animal):
    def __init__(self, age: int = None, gender: int = None) -> None:
        print("Call the constructor of Tiger.")
        self.m_name = "Tiger"
        super().__init__(age, gender)
        print("Ends the call to Tiger's constructer.")

    def eat(self):
        print("Tiger is eating")

    pass


class Lion(Animal):
    def __init__(self, age: int = None, gender: int = None) -> None:
        print("Call the constructor of Lion.")
        self.m_name = "Lion"
        super().__init__(age, gender)
        print("Ends the call to Lion's constructer.")

    def eat(self):
        print("Lion is eating")

    def sleep(self):
        print("Lion is sleeping")
    pass


class Liger(Tiger, Lion):
    def __init__(self, age: int = None, gender: int = None) -> None:
        super().__init__(age, gender)
    pass


if __name__ == '__main__':
    liger = Liger(8, 1) #實(shí)例化一個(gè)`Liger`
    print(Liger.__mro__)
    print(liger.m_name)
    liger.eat()
    liger.sleep()

運(yùn)行輸出為:

Call the constructor of Tiger.
Call the constructor of Lion.
Call the constructor of Animal.
Ends the call to Animal's constructer.
Ends the call to Lion's constructer.
Ends the call to Tiger's constructer.
(<class '__main__.Liger'>, <class '__main__.Tiger'>, <class '__main__.Lion'>, <class '__main__.Animal'>, <class 'object'>)
Animal
Tiger is eating
Lion is sleeping

  • 繼承順序:通過(guò)構(gòu)造函數(shù)的打印順序和Ligermro(顯示繼承順序)可以看到,繼承順序?yàn)?code>Liger -> Tiger -> Lion -> Animal。多繼承時(shí),繼承順序一般為從左到右,從下到上。
  • 同名變量:Animal,TigerLion的初始化函數(shù)中都初始化了m_name變量,卻并沒(méi)有同C++中的繼承沖突一樣出現(xiàn)多份m_name的拷貝,而是只對(duì)Liger的實(shí)例liger進(jìn)行動(dòng)態(tài)地修改同一塊內(nèi)存地址,由于Animal的初始化函數(shù)最后被調(diào)用,所以m_name賦值為Animal
  • 同名函數(shù):
    • 對(duì)于Liger的兩父類(lèi)Tiger,Lion和其祖先Animal都定義過(guò)的函數(shù)eatLiger類(lèi)總是選擇最左父類(lèi)的同名函數(shù),所以調(diào)用Liger.eat()得到的是Tiger.eat()。
    • 而如果并不是所有父類(lèi)都定義過(guò)的函數(shù),子類(lèi)在類(lèi)型樹(shù)上從左到右尋找第一個(gè)定義過(guò)該函數(shù)的父類(lèi)。例如Liger.sleep(),Tiger中并未定義sleep(),所以找到了后面的Lion.sleep()。

小結(jié):對(duì)于簡(jiǎn)單的菱形繼承,可以大致認(rèn)為其是在類(lèi)型樹(shù)上按照"從左到右,從上到下"的廣度優(yōu)先遍歷順序查找成員的。

復(fù)雜的菱形繼承

對(duì)于復(fù)雜的菱形繼承,有時(shí)候按照上面的廣度優(yōu)先遍歷類(lèi)型樹(shù)得到的繼承順序并不正確。例如:

這時(shí)如果使用廣度優(yōu)先遍歷得到的繼承順序?yàn)椋?code>M A B Z X Y object。

運(yùn)行如下Python代碼得到的繼承順序?yàn)椋?/p>

class X(object):
    pass

class Y(object):
    pass


class Z(object):
    pass


class A(X, Y):
    pass


class B(Y, Z):
    pass


class M(A, B, Z):
    pass

print(M.mro())

# [<class '__main__.M'>, 
<class '__main__.A'>,
<class '__main__.X'>, 
<class '__main__.B'>,
<class '__main__.Y'>, 
<class '__main__.Z'>,
<class 'object'>]

繼承順序?yàn)?code>M A X B Y Z object。

查閱資料得知,這是因?yàn)樵?code>Python2.3以后的版本,類(lèi)的繼承順序求法采用了C3算法,以保證繼承的單調(diào)性原則。(子類(lèi)不能改變基類(lèi)的MRO搜索順序)

MRO C3 算法

算法原理

C3(C3 linearization)算法實(shí)現(xiàn)保證了三種重要特性:

  • 繼承拓?fù)鋱D的一致性。
  • 局部?jī)?yōu)先原則。
  • 單調(diào)性原則。

在C3算法中,把L[C]定義為類(lèi)C的的linearization值(也就是MRO里的繼承順序,后面簡(jiǎn)稱L值),計(jì)算邏輯如下:

L[C] = C + merge of linearization of parents of C and list of parents of C in the order they are inherited from left to right. 

L[C]是所有父類(lèi)的L值的merge。

運(yùn)算規(guī)則為:

其中 C 多繼承父類(lèi) B 1 . . B N

merge的運(yùn)算方法如下:

  • 對(duì)于merge的參數(shù)列表,從左到右檢查每個(gè)參數(shù)的第一個(gè)元素,記為H。
  • 如果H不出現(xiàn)在其它參數(shù)中,或者出現(xiàn)在某個(gè)參數(shù)中且是該參數(shù)第一個(gè)元素(頭),則從所有列表中刪去H并添加到C的后面形成C1。(即H不被C的所有父類(lèi)繼承,以保證L值的單調(diào)性)

重復(fù)上述步驟直至列表為空或者不能找出可以輸出的元素。

算法例子

拿上面的繼承來(lái)舉例:

從上至下一次計(jì)算object,X,Y,Z,A,B,M的繼承順序:

L[object] = O(object)。

L[X] = X + merge(L[object]) = X + O = XO,同理L[Y] = YOL[Z] = ZO。

L[A] = A+merge(L[X],L[Y],XY)
     = A + merge(XO,YO,XY) 
	 = AX + merge(O,YO,Y)
	 = AXY + merge(O,O)
	 = AXYO

L[B] = B + merge(L[Y],L[Z],YZ)
     = B + merge(YO,ZO,YZ)
     = BY + merge(O,ZO,Z)
     = BYZ + merge(O,O)
     = BYZO

然后是M的繼承順序計(jì)算:

L[M] = M + merge(L[A],L[B],L[Z],ABZ)
     = M + merge(AXYO,BYZO,ZO,ABZ)
     = MA + merge(XYO,BYZO,ZO,BZ)
     = MAX + merge(YO,BYZO,ZO,BZ) #第一個(gè)參數(shù)中Y被第二個(gè)參數(shù)中的Z繼承,所以檢查第二個(gè)參數(shù)的第一個(gè)元素即 B
     = MAXB + merge(YO,YZO,ZO,Z)
     = MAXBY + merge(O,ZO,ZO,Z) #同樣,O被Z繼承
     = MAXBYZ + merge(O,O,O)
     = MAXBYZO

得到類(lèi)M的最終繼承順序MAXBYZO。

算法實(shí)現(xiàn)

下面是其它資料中找到的Wiki百科上對(duì)該算法的Python版本實(shí)現(xiàn):

def c3MRO(cls):
    if cls is object:
        # 討論假設(shè)頂層基類(lèi)為object,遞歸終止
        return [object]

    # 構(gòu)造C3-MRO算法的總式,遞歸開(kāi)始
    mergeList = [c3MRO(baseCls) for baseCls in cls.__bases__]
    mergeList.append(list(cls.__bases__))
    mro = [cls] + merge(mergeList)
    return mro


def merge(inLists):
    if not inLists:
        # 若合并的內(nèi)容為空,返回空l(shuí)ist
        # 配合下文的排除空l(shuí)ist操作,遞歸終止
        return []

    # 遍歷要合并的mro
    for mroList in inLists:
        # 取head
        head = mroList[0]
        # 遍歷要合并的mro(與外一層相同),檢查尾中是否有head
        ### 此處也遍歷了被取head的mro,嚴(yán)格地來(lái)說(shuō)不符合標(biāo)準(zhǔn)算法實(shí)現(xiàn)
        ### 但按照多繼承中地基礎(chǔ)規(guī)則(一個(gè)類(lèi)只能被繼承一次),
        ### head不可能在自己地尾中,無(wú)影響,若標(biāo)準(zhǔn)實(shí)現(xiàn),反而增加開(kāi)銷(xiāo)
        for cmpList in inLists[inLists.index(mroList) + 1:]:
            if head in cmpList[1:]:
                break
        else:
            # 篩選出好head
            nextList = []
            for mergeItem in inLists:
                if head in mergeItem:
                    mergeItem.remove(head)
                if mergeItem:
                    # 排除空l(shuí)ist
                    nextList.append(mergeItem)
            # 遞歸開(kāi)始
            return [head] + merge(nextList)
    else:
        # 無(wú)好head,引發(fā)類(lèi)型錯(cuò)誤
        raise TypeError

測(cè)試:

class A(object):pass
class B(object):pass
class C(object):pass
class E(A,B):pass
class F(B,C):pass
class G(E,F):pass

print([i.__name__ for i in c3MRO(G)])

輸出結(jié)果:

['G', 'E', 'A', 'F', 'B', 'C', 'object']

參考資料

到此這篇關(guān)于一文講解python中的繼承沖突及繼承順序的文章就介紹到這了,更多相關(guān)python 繼承沖突及繼承順序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:

相關(guān)文章

  • Python 日志logging模塊用法簡(jiǎn)單示例

    Python 日志logging模塊用法簡(jiǎn)單示例

    這篇文章主要介紹了Python 日志logging模塊用法,結(jié)合簡(jiǎn)單實(shí)例形式分析了Python 日志logging模塊功能、原理及日志輸出到控制臺(tái)與文件的相關(guān)操作技巧,需要的朋友可以參考下
    2019-10-10
  • pycharm設(shè)置默認(rèn)的UTF-8編碼模式的方法詳解

    pycharm設(shè)置默認(rèn)的UTF-8編碼模式的方法詳解

    這篇文章主要介紹了pycharm設(shè)置默認(rèn)的UTF-8編碼模式,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 用python畫(huà)城市輪播地圖

    用python畫(huà)城市輪播地圖

    輪播地圖可以在很多方面有實(shí)際應(yīng)用,所以就介紹給大家,并給出個(gè)實(shí)際操作案例,感興趣的朋友可以參考下
    2021-05-05
  • Python Locust負(fù)載測(cè)試工具安裝配置使用詳解

    Python Locust負(fù)載測(cè)試工具安裝配置使用詳解

    本文將提供有關(guān)Python Locust的全面指南,包括安裝和配置、基本概念、性能測(cè)試、任務(wù)編寫(xiě)、報(bào)告生成以及實(shí)際應(yīng)用場(chǎng)景,將通過(guò)豐富的示例代碼來(lái)幫助深入理解Locust的使用
    2024-01-01
  • Python處理application/json錯(cuò)誤的方法詳解

    Python處理application/json錯(cuò)誤的方法詳解

    這篇文章主要為大家詳細(xì)介紹了python使用httpx_sse調(diào)用sse流式接口對(duì)響應(yīng)格式為application/json的錯(cuò)誤信息處理的相關(guān)知識(shí),需要的可以了解下
    2025-02-02
  • 使用Python和Spire.XLS輕松實(shí)現(xiàn)Excel到TXT數(shù)據(jù)轉(zhuǎn)換

    使用Python和Spire.XLS輕松實(shí)現(xiàn)Excel到TXT數(shù)據(jù)轉(zhuǎn)換

    在數(shù)據(jù)處理和分析的過(guò)程中,經(jīng)常需要將不同格式的數(shù)據(jù)進(jìn)行轉(zhuǎn)換,Excel?文件是數(shù)據(jù)存儲(chǔ)和操作中非常常見(jiàn)的格式,而?TXT?文件憑借其簡(jiǎn)單的文本格式,本文將介紹如何使用?Python?和?Spire.XLS?庫(kù)將?Excel?導(dǎo)出為?TXT?文件,需要的朋友可以參考下
    2026-02-02
  • 如何利用Python實(shí)現(xiàn)自動(dòng)打卡簽到的實(shí)踐

    如何利用Python實(shí)現(xiàn)自動(dòng)打卡簽到的實(shí)踐

    簽到,都是規(guī)律性的操作,何嘗不寫(xiě)一個(gè)程序加到Windows實(shí)現(xiàn)自動(dòng)簽到呢,本文就主要介紹了如何利用Python實(shí)現(xiàn)自動(dòng)打卡簽到的實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-12-12
  • 解決Jupyter notebook更換主題工具欄被隱藏及添加目錄生成插件問(wèn)題

    解決Jupyter notebook更換主題工具欄被隱藏及添加目錄生成插件問(wèn)題

    這篇文章主要介紹了解決Jupyter notebook更換主題工具欄被隱藏及添加目錄生成插件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04
  • python list轉(zhuǎn)矩陣的實(shí)例講解

    python list轉(zhuǎn)矩陣的實(shí)例講解

    今天小編就為大家分享一篇python list轉(zhuǎn)矩陣的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • python中DDT數(shù)據(jù)驅(qū)動(dòng)的實(shí)現(xiàn)

    python中DDT數(shù)據(jù)驅(qū)動(dòng)的實(shí)現(xiàn)

    DDT是一種軟件測(cè)試方法,本文主要介紹了python中DDT數(shù)據(jù)驅(qū)動(dòng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04

最新評(píng)論

安远县| 临猗县| 盐津县| 临汾市| 浑源县| 东明县| 黎城县| 越西县| 泗阳县| 静海县| 赤城县| 霍州市| 瑞安市| 大邑县| 武穴市| 常德市| 奇台县| 重庆市| 西贡区| 曲靖市| 彰武县| 滕州市| 峨山| 泊头市| 安福县| 富宁县| 合江县| 凌海市| 贡山| 化德县| 普兰店市| 图木舒克市| 洛隆县| 察哈| 华阴市| 东丽区| 甘孜县| 眉山市| 浏阳市| 十堰市| 惠安县|