Python_類的繼承

1.類的繼承關係和生活中父親、兒子、孫子之間的關係一樣,Python中若A類繼承B類,則A類稱之為子類,B類稱之為父類(也稱為基類)。 2.類的繼承方式分為:單繼承、多繼承兩種; 類的單繼承是指,A類只繼承一個父類B,如下圖所示:

類的多繼承是指,A類可以繼承多個父類,如下圖所示:

3.類繼承的順序 如果子類繼承一個或多個父類時,子類屬性是任何調用的呢?見下圖實例,我們定義的患者類繼承了醫院類和衛生局類,問題1.患者類和醫院類中具有登記的方法(regpatien),此時子類調用該方法時是怎樣調用的呢?問題2.子類中沒有addr的屬性,而兩個父類中存在addr屬性,此時子類在調用addr屬性時能否正常調用?如果能正常調用,調用的又是哪個父類的addr屬性? 問題1.見下圖:

問題2.1.如果子類繼承父類的順序為先Hospital後Healthbureau,如下圖所示:

問題2.2.如果子類繼承父類的順序為先Healthbureau後Hospital,如下圖所示:

總結:1.子類繼承父類時,在子類進行屬性調用的順序為:先查找自己的屬性字典,若自己的屬性字典中無該屬性,則會依次按照繼承父類的順序來依次查找父類的屬性字典;2.子類繼承父類,當父類和子類均有相同的屬性時,子類並不會影響父類的屬性。總結起來就是:按繼承的順序來依次查詢屬性,一旦查到則停止;子類和父類的屬性相互獨立,互不影響;子類可以調用父類的屬性,反之不行; 該部分的程式碼塊為:

class Hospital():      "醫院類-->父類"      addr = "醫院地址為:無錫市解放路"      depertment = ["超聲科","放射科","內鏡科"]      def __init__(self,name,type,price):          self.name = name          self.type = type          self.price = price      def regpatien(self):          print("--->>醫院正在登記患者")    class Healthbureau():      "衛生局類"      addr = "衛生局類地址為:無錫市中心大夏"      def __init__(self,heigh,size):          self.heigh =heigh          self.size =size    # class Patient(Hospital,Healthbureau):   #多繼承,先Hospital後Healthbureau  class Patient(Healthbureau,Hospital):   #多繼承,先Healthbureau後Hospital      "患者類"      def __init__(self,patientname,age,sex):          self.patientname = patientname          self.age = age          self.sex =sex      def regpatien(self):          print("--->>患者已經成功成功")      def tohispital(self):          print("%s去%s檢查"%(self.patientname,Hospital.depertment[2]))    #子類實例化  patient1 = Patient("李明",24,"男")  #父類Hospital實例化  hospital = Hospital("無錫市人民醫院","江蘇省無錫市人民大道","三甲")  #子類實例調用regpatien方法  patient1.regpatien()  #父類Hospital調用regpatien方法  hospital.regpatien()  #子類實例調用addr方法  print(patient1.addr)

深度解析類繼承順序 如何解析多層繼承關係? 多層繼承在python2和python3中解析的順序不同,python2中是深度優先的原則,python3中是以廣度優先的原則。繼承順序見下圖:

繼承原理:python到底是如何實現繼承順序的呢?對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表。 為了實現繼承,python會在MRO列表上從左到右查找基類,直到找到第一個匹配這個屬性的類為止。而這個MRO列表的構造是通過一個C3線性化演算法來實現的。這個演算法實際上就是合併所有父類的,MRO列表並遵循如下三條準則: ① 子類會由於父類被檢查; ② 多個父類會根據他們在列表中的順序被檢查; ③ 如果對於下一個類存在兩個合法的選擇,應選擇第一個父類;

為此我們可以直接使用子類的mro或者mro方法來查詢它自身的繼承順序,如下圖所示:

4.介面繼承 從上面例子中我們可以看出,類的繼承有2種含義,一是:子類繼承基類的方法,並作出自己的擴展或改變(基類程式碼的重用);二是:聲明某個子類兼容於某基類,父類定義一個介面類,子類繼承介面類,並且實現介面類中定義的方法。 實踐中,繼承的第一種含義常常不建議使用,它是利小於弊,會出現程式碼的強耦合,不利於後面的維護和擴展;但介面的第二中含義十分重要,又稱之為』介面繼承』。 介面繼承實質上是:「要求做出一個抽象,這個抽象規定了一個兼容介面,使得外部調用者無需了解具體細節,可一視同仁的處理實現了特定介面的所有對象。」這種在程式設計上稱之為歸一化。 例如:定義一個學校的基類,學校有不能的課程、學校有不同的活動,但是幼兒園的課程只是簡單的字母識別、數數等,而大學的課程包含了微積分、專業課程等。如下圖所示,通過介面的繼承來實現上面的要求:

如果Kindergarten類或College類中沒有定義course或activity函數時,實例化直接報錯,如下圖所示:

所以,介面繼承就是在基類中定義子類要實現的方法名稱(使用@abc.abstractclassmethod來裝飾該函數,但它並未無實際功能),這樣繼承它的子類就必須要自定義這個函數功能,若子類沒有該函數,則開始實例化就會報錯。 這樣我們如果知道某些類要實現某些相同名稱但功能不能的函數時,就可以先定義一個父類,再在父類中定義必須要實現的功能。這樣子類在繼承父類時,就可以避免忘記必須要實現的功能函數了,它是用來規範子類的方法。實際上基類不用進行實例化操作,因為它完全沒有意義。 該部分的程式碼塊為:

import abc  class School(metaclass=abc.ABCMeta):      "學校的基類"      @abc.abstractclassmethod      def course(self):          "學校開課的方法"          pass      @abc.abstractclassmethod      def activity(self):          "校園活動的方法"          pass    class Kindergarten(School):      "幼兒園的類"      def __init__(self,name,addr,number):          self.name =name          self.addr =addr          self.number =number      def course(self):          "課程函數"          print("%s開設了字母、識數等課程"%self.name)      def activity(self):          "比賽活動"          print("%s參加了兒童舞蹈比賽"%self.number)    class College(School):      "幼兒園的類"      def __init__(self, name, addr, number):          self.name = name          self.addr = addr          self.number = number      # def course(self):      #     "課程函數"      #     print("%s開設了微積分、高等數學等課程" % self.name)      def activity(self):          "比賽活動"          print("%s參加了大學口語比賽"%self.name)      def  volunta(self):          "義務活動"          print("這是志願者活動")    kindergarten =Kindergarten("文瀾幼兒園","杭州市拱墅區",300)  kindergarten.activity()    college =College("浙江大學","杭州市上城區",65300)  college.course()