亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

簡單的菱形繼承

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

設(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

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

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

復(fù)雜的菱形繼承

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

這時(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以后的版本,類的繼承順序求法采用了C3算法,以保證繼承的單調(diào)性原則。(子類不能改變基類的MRO搜索順序)

MRO C3 算法

算法原理

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

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

在C3算法中,把L[C]定義為類C的的linearization值(也就是MRO里的繼承順序,后面簡稱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值的merge。

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

其中 C 多繼承父類 B 1 . . B N

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

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

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

算法例子

拿上面的繼承來舉例:

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

L[object] = O(object)

L[X] = X + merge(L[object]) = X + O = XO,同理L[Y] = YO,L[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

得到類M的最終繼承順序MAXBYZO

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

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

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

    # 構(gòu)造C3-MRO算法的總式,遞歸開始
    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)容為空,返回空list
        # 配合下文的排除空list操作,遞歸終止
        return []

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

測試:

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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:

相關(guān)文章

  • pytorch+sklearn實(shí)現(xiàn)數(shù)據(jù)加載的流程

    pytorch+sklearn實(shí)現(xiàn)數(shù)據(jù)加載的流程

    這篇文章主要介紹了pytorch+sklearn實(shí)現(xiàn)數(shù)據(jù)加載,之前在訓(xùn)練網(wǎng)絡(luò)的時(shí)候加載數(shù)據(jù)都是稀里糊涂的放進(jìn)去的,也沒有理清楚里面的流程,今天整理一下,加深理解,也方便以后查閱,需要的朋友可以參考下
    2022-11-11
  • Python抓取網(wǎng)頁圖片難點(diǎn)分析

    Python抓取網(wǎng)頁圖片難點(diǎn)分析

    沒想到python是如此強(qiáng)大,令人著迷,以前看見圖片總是一張一張復(fù)制粘貼,現(xiàn)在好了,學(xué)會python就可以用程序?qū)⒁粡垙垐D片,保存下來。今天網(wǎng)上沖浪看到很多美圖,可是圖片有點(diǎn)多,不想一張一張地復(fù)制粘貼,怎么辦呢?辦法總是有的,即便沒有我們也可以創(chuàng)造一個(gè)辦法
    2023-01-01
  • Python如何實(shí)現(xiàn)的二分查找算法

    Python如何實(shí)現(xiàn)的二分查找算法

    在本篇文章里小編給大家分享的是一篇關(guān)于Python實(shí)現(xiàn)的二分查找算法實(shí)例講解內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-05-05
  • Celery批量異步調(diào)用任務(wù)一直等待結(jié)果問題

    Celery批量異步調(diào)用任務(wù)一直等待結(jié)果問題

    這篇文章主要介紹了Celery批量異步調(diào)用任務(wù)一直等待結(jié)果問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • python list排序的兩種方法及實(shí)例講解

    python list排序的兩種方法及實(shí)例講解

    本文主要介紹了python list排序的兩種方法及實(shí)例講解。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-03-03
  • python利用pandas將excel文件轉(zhuǎn)換為txt文件的方法

    python利用pandas將excel文件轉(zhuǎn)換為txt文件的方法

    今天小編就為大家分享一篇python利用pandas將excel文件轉(zhuǎn)換為txt文件的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • Python自動化辦公之Excel數(shù)據(jù)的寫入

    Python自動化辦公之Excel數(shù)據(jù)的寫入

    這篇文章主要為大家詳細(xì)介紹一下Python中excel的寫入模塊- xlsxwriter,并利用該模塊實(shí)現(xiàn)Excel數(shù)據(jù)的寫入,感興趣的小伙伴可以了解一下
    2022-05-05
  • python+tkinter實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    python+tkinter實(shí)現(xiàn)學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了python+tkinter實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Python數(shù)據(jù)分析之雙色球基于線性回歸算法預(yù)測下期中獎結(jié)果示例

    Python數(shù)據(jù)分析之雙色球基于線性回歸算法預(yù)測下期中獎結(jié)果示例

    這篇文章主要介紹了Python數(shù)據(jù)分析之雙色球基于線性回歸算法預(yù)測下期中獎結(jié)果,涉及Python基于線性回歸算法的數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2018-02-02
  • Python流程控制常用工具詳解

    Python流程控制常用工具詳解

    這篇文章主要介紹了Python流程控制常用工具詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02

最新評論