繼承有兩種用途:
1. 繼承基類的方法,而且作出本身的改變或者擴展(代碼重用)
2. 申明某個子類兼容於某基類,定義一個接口類interface,接口類定義了一些接口名且未實現接口的功能,子類繼承接口類,而且實現接口中的功能java
class Wechat: ''' 微信支付 ''' def pay(self, money): print('已經用微信支付%s元.' % money) class Alipay: ''' 支付寶支付 ''' def pay(self, money): print('已經用支付寶支付%s元.' % money) def pay(pay_obj, money): ''' 支付函數,整體負責支付 對應支付的對象和要支付的金額 ''' pay_obj.pay(money) ali = Alipay() pay(ali, 200)
若是咱們又定義了一個支付類且沒有定義pay方法:python
class Wechat: ''' 微信支付 ''' def pay(self, money): print('已經用微信支付%s元.' % money) class Alipay: ''' 支付寶支付 ''' def pay(self, money): print('已經用支付寶支付%s元.' % money) class Applepay: def fuqian(self, money): print('已經用Applepay支付%s元.' % money) def pay(pay_obj, money): ''' 支付函數,整體負責支付 對應支付的對象和要支付的金額 ''' pay_obj.pay(money) # 由於 Applepay 類中未定義 pay 方法 ali = Alipay() pay(ali, 200) apple = Applepay() pay(apple, 300) # 報錯
經過上面的例子,報錯是由於 Applepay 類中沒有定義 pay 方法。在這裏咱們能夠經過繼承的關係來手動拋出異常。微信
class Payment: # 建立一個基類 def pay(self, money): # 基類中包含 pay 方法 raise NotImplemented # 主動拋出異常 class Wechat(Payment): ''' 微信支付 ''' def pay(self, money): print('已經用微信支付%s元.' % money) class Alipay(Payment): ''' 支付寶支付 ''' def pay(self, money): print('已經用支付寶支付%s元.' % money) class Applepay(Payment): def fuqian(self, money): print('已經用Applepay支付%s元.' % money) def pay(pay_obj, money): ''' 支付函數,整體負責支付 對應支付的對象和要支付的金額 ''' pay_obj.pay(money) ali = Alipay() pay(ali, 200) apple = Applepay() pay(apple, 300) # 報錯
已知 Applepay 類中沒有 pay 方法,則會去基類中尋找,基類中定義的 pay 方法是主動拋出異常。
可使用 abc 模塊來實現接口,自動的去檢查是否實現了某方法app
from abc import ABC, abstractclassmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractclassmethod def pay(self, money): raise NotImplemented class Wechat(Payment): ''' 微信支付 ''' def pay(self, money): print('已經用微信支付%s元.' % money) class Alipay(Payment): ''' 支付寶支付 ''' def pay(self, money): print('已經用支付寶支付%s元.' % money) class Applepay(Payment): def fuqian(self, money): print('已經用Applepay支付%s元.' % money) def pay(pay_obj, money): ''' 支付函數,整體負責支付 對應支付的對象和要支付的金額 ''' pay_obj.pay(money) ali = Alipay() pay(ali, 200) apple = Applepay() # 實例化就能檢查出子類是否建立了 pay 方法
實踐中,單純的從子類繼承父類的意義不大,甚至有害,由於它使得子類與基類出現強耦合。
繼承的第二種含義就很是重要,它又叫‘接口繼承’
接口繼承實質上是要求‘作出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無需關心具體細節,可一視同仁的處理,實現了特定接口的全部對象’ -- 這在程序設計上,叫作歸一化。
歸一化使得高層的外部使用者能夠不加區分的處理全部接口兼容的對象集合。函數
什麼是抽象類:微信支付
與java同樣,python也有抽象類的概念可是一樣須要藉助模塊實現,抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化。
爲何要有抽象類:
若是說類是從一堆對象中抽取相同的內容而來的,那麼抽象類就是從一堆類中抽取相同的內容而來的,內容包括數據屬性和函數屬性。
好比咱們有香蕉的類,有蘋果的類,有桃子的類,從這些類抽取相同的內容就是水果這個抽象的類,你吃水果時,
要麼是吃一個具體的香蕉,要麼是吃一個具體的桃子。。。。。。你永遠沒法吃到一個叫作水果的東西。
從設計角度去看,若是類是從現實對象抽象而來的,那麼抽象類就是基於類抽象而來的。
從設計角度去看,若是類是從現實對象抽象而來的,那麼抽象類就是基於類抽象而來的。
從實現角度來看,抽象類與普通類的不一樣之處在於:抽象類中有抽象方法,該類不能被實例化,只能被繼承,且子類必須實現抽象方法。
這一點與接口有點相似,但實際上是不一樣的,即將揭曉答案spa
#一切皆文件 import abc #利用abc模塊實現抽象類 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定義抽象方法,無需實現功能 def read(self): '子類必須定義讀功能' pass @abc.abstractmethod #定義抽象方法,無需實現功能 def write(self): '子類必須定義寫功能' pass # class Txt(All_file): # pass # # t1=Txt() #報錯,子類沒有定義抽象方法 class Txt(All_file): #子類繼承抽象類,可是必須定義read和write方法 def read(self): print('文本數據的讀取方法') def write(self): print('文本數據的讀取方法') class Sata(All_file): #子類繼承抽象類,可是必須定義read和write方法 def read(self): print('硬盤數據的讀取方法') def write(self): print('硬盤數據的讀取方法') class Process(All_file): #子類繼承抽象類,可是必須定義read和write方法 def read(self): print('進程數據的讀取方法') def write(self): print('進程數據的讀取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #這樣你們都是被歸一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
抽象類與接口類設計
抽象類的本質仍是類,指的是一組類的類似性包括數據屬性(如all_type)和函數屬性(如read、write),而接口只強調函數屬性的類似性。
抽象類是一個介於類和接口直接的一個概念,同時具有類和接口的部分特性,能夠用來實現歸一化設計
在python中,並無接口類這種東西,即使不經過專門的模塊定義接口,咱們也應該有一些基本的概念。code