繼承、抽象類、多繼承

# 繼承的引子# 假設咱們如今有一個遊戲,遊戲中有這些具體的事物(對象 ): 梅西、奧巴馬、史努比、史派克、小豬配齊、豬八戒。# 採起面向對象設計的方法,是要對遊戲中的具體對象,進行分門別類的抽象,抽取中類似對象的共同特徵和行爲來,做爲一種規範,# 一種模板來,梅西和奧巴馬,它們的類似,具備人的特徵,所以,咱們把它們歸爲一類,即人類,就抽象出人類這一律念來了。# 史努力和史派克 具備共同的特徵和行爲,咱們把它們歸爲一類,並取名爲狗類,完成具體到綜合的第一次抽象,而小豬配齊和希豬八戒,# 它們兩個具體的事物,又具備共性的東西,所以將它們歸爲一類,並取名爲豬類。# 以上,經過對抽取類似具體事物的共同特徵,歸爲一類,完成了事物的第一層抽象。#  梅西、奧巴馬、史努比、史派克、小豬配齊、豬八戒 ===》  人類 、狗類 、 豬類  # 基本的分類#  人類 、狗類 、 豬類 ===》 通過再一次抽象,抽象出 動物類。# 所以面向對象的過程,就是由具體  到 抽象 的過程。從宏觀上,概念上 統領類似事物。抽象的層次,越高,可以描述和規範的事物就越多。# # 貓類:#     屬性: 名字,品種,食物#     方法: 叫,抓老鼠,吃,喝# 狗類:#     屬性: 名字,品種,食物#     方法:叫,看家,吃,喝# 人類:#     屬性:名字,品種,食物#     方法:說話,工做,吃,喝# 雖然,咱們從具體的事物,抽象出三個類別,可是咱們發現,這三類之間,還有共同的代碼,沒有提升代碼的重用性。# 因而乎,咱們能夠將三個類別的共同代碼,再抽取出來,創建一個類別,好比說叫動物類,它讓貓類、狗類、人類隸屬於這個類,# 也就具備這個類的屬性。# 那麼用puthon代碼如何實現呢?# 定義 一個 Animal() 的父類class Animal:    # 父類,超類,基類    def __init__(self,name,kind,food,language):        self.name = name        self.kind = kind        self.food = food        self.language = language    def yell(self):        print("%s叫" % self.language)    def eat(self):        print("吃%s" % self.food)    def drink(self):        print("喝水")# 定義 類的 時候 ,繼承某個類,它將繼承父類的全部屬性 和 方法,繼承的寫法,就是將類 要繼承的父類,放在類名後面的小括號裏。class Cat(Animal):   # 派生類    def catch_mouse(self):        print("抓老鼠")class Dog(Animal):  # 派生類    def __init__(self,name,kind,food,language,eye_color):  # 子類重寫父類的方法,並經過super()方法,調用父類的同名方法        self.eye_color = eye_color                          # 派生屬性        super().__init__(name,kind,food,language) # self ,不用傳,會自動傳    def swim(self):            # 派生方法        print("游泳")    def look_afte_home(self):        print("看家")class Human(Animal):  # 派生類    def __init__(self):               # 這裏子類對父類的方法,進行了重寫,即覆蓋了父類,此時父類的同名方法,對子類就不可見了。        self.walk_way = "直立行走"    def work(self):        print("工做")# 在繼承關係中,被繼承的類,咱們稱之爲超類/基類/父類, : 好比上面的 Animal類# 繼承的類,叫作子類/派生類: 好比上面的 Cat, Dog, Person# 繼承與重用:是同一個事物的兩方面,類的繼承就是了爲提升代碼的重用性,提升代碼的重用性,除了函數,類就是別外一種的實現方式。# 好比說:寫了兩個類或多個類,它們有共同的代碼或邏輯,這時候就能夠爲它們建立一個父類,把共同的代碼或邏輯放到父類裏,這時經過繼承# 就實現了代碼的重用性。# 繼承與重用,父類中的全部方法和屬性都被子類中使用了。阿貓 = Cat("阿貓","花貓","魚","喵喵")阿貓.yell()阿貓.eat()阿貓.drink()print(阿貓.name)yellDog = Dog("黃狗","土狗","骨頭","汪汪","藍色")yellDog.eat()yellDog.drink()yellDog.yell()print(yellDog.name)xiaomin = Human()                   # 由於子類對父類的 __init__方法,進行了重寫,除了self之外,沒有參數,不須要手動傳參。print(xiaomin.walk_way)yellDog.swim()# 總結:當子類當中有要被調用的方法 和 屬性的時候,子類的對象會直接選擇子類中的方法、變量,父類中的同名方法不會被自動執行。# 若是咱們既想要執行子類中方法,也想要執行父類中的同名方法,那麼須要在子類的方法中調用父類的方法:有兩種方式:# 父類名.方法名(...)# super().方法名(...)# 面試題:class Foo:    def __init__(self):  # 初始化對象實例的函數,此函數僅在調用 類名() 時執行一次        self.func()     # 對象調用    def func(self):        print('in Foo')class Son(Foo):    # def func(self):    #     print("in Son")    passs1 = Son()      # 建立了一個Son類的對象實例,並賦值給對象引用 s1。過程是,在內存中開闢一個對象空間,根據對象所屬的直接類的類#對象指針 找尋 __init__方法執行,子類沒有,在父類中尋找,找到將對象傳遞參數self,執行 __init__函數體,執行self.func()語句,# 對象執行一個方法,先在對象所屬直接類中,找到,直接執行,沒有找到,再到父類找,因此此處是打印 in Son# class Foo:#     Country = 'China'#     def func(self):#         print(self.Country)## class Son(Foo):#     Country = 'English'#     def func(self):     # 走這個方法#         print(self.Country)## s = Son()# s.func()# class Foo:#     Country = 'China'#     def func(self):  # 走這個方法#         print(self.Country)## class Son(Foo):#     Country = 'English'## s = Son()# s.func()   # English# class Foo:#     Country = 'China'#     def func(self):#         print(self.Country)## class Son(Foo):pass## s = Son()# s.func()   # 'China'# 結論:始終注意,那個對象調用 ,self就是哪一個對象# 抽象類# 工做中 公司使用抽象類 ,來規範 開發的規則。# 源碼 別人使用抽象類from abc import ABCMeta,abstractmethod   # 從 abc 這個外部模塊中,導入 ABCMeta 類 和 abstracmethod這個用於裝飾函數的裝飾器class Payment(metaclass=ABCMeta):  # 給類的元類,傳遞一個關鍵字參數    @abstractmethod    def pay(self):pass    # 抽象方法,僅有定義,沒有方法的實現    @abstractmethod    def shouqian(self):pass            # 假如,把這兩行的註釋打開,若是子類不實現這個方法,程序會報錯                                    #    a = Alipay()                                       # TypeError: Can't instantiate abstract class Alipay with abstract methods shouqian    def abstract(self):        print("我繼承抽象類")class Alipay(Payment):    def pay(self,money):        print("使用支付寶支會了%s元" % money)    def shouqian(self,money):        print("使用收款方式收到%s元" % money)class Wechatpay(Payment):    def pay(self,money):        print("使用微信支付了%s元" % money)    def shouqian(self,money):        print("使用收款方式收到%s元" % money)class Applepay(Payment):    def pay(self,money):        print("使用applepay支付了%s元" % money)    def shouqian(self,money):        print("使用收款方式收到%s元" % money)# def pay(obj,money):#     obj.pay(money)a = Alipay()a.pay(100)a.shouqian(2000)a.abstract()     # 抽象類,也能夠有普通方法,子類繼承wechat = Wechatpay()wechat.pay(260)wechat.shouqian(489)apple = Applepay()apple.pay(159)apple.shouqian(6000)# 以上多個子類,繼承同一個抽象類,子類必須去實現抽象類中用@abstractmethod裝飾器裝飾的方法,不然會報錯。# 實現了不一樣的對象,調用相同的方法# 在上面的基礎上,咱們來定義 一個 統一的函數,也能夠叫接口def 付錢(obj,money):    obj.pay(money)#  這樣,func()就是一個統一的支付接口付錢(wechat,1600)付錢(a,3500)def 收錢(obj,money):    obj.shouqian(money)收錢(a,10000)收錢(apple,30000)# p = Payment()    # 抽象類 , 不能實例化 TypeError: Can't instantiate abstract class Payment with abstract methods pay, shouqian# 總結: 抽象類 是一種 規範#  多人開發、複雜的需求、後期的擴展# 手段,來幫助咱們完成規範。# 抽象類 如何建立#  抽象類是一個規範,它基本上不會實現什麼具體的功能,抽象類是不能被實例化的。# 要想寫一個抽象類的步驟:#   from abc  import ABCMeta,abstractmethod#   在建立這個類的時候,指定 metaclass = ABCMeta#   在你但願子類實現的方法上加一個 @abstractmethond 裝飾器#  使用抽象類:#   繼承這個類#   必須實現這個類中被 @abstractmehond 裝飾器裝飾的方法
相關文章
相關標籤/搜索