本篇文章給大家分享的內容是關於Python物件導向之繼承和多態,有著一定的參考價值,有需要的朋友可以參考一下
在OOP程式設計中,當我們定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類別(Subclass),而被繼承的class稱之為基底類別、父類別或超類別(Base class、Supper class)。
例如,我們已經寫了一個名為Animal的class,有個run()方法可以直接列印:
class Animal(object): def run(self): print('Animal is running...')
當我們需要寫Dog和Cat類別時,就可以直接從Animal類別繼承:
class Dog(Animal): pass class Cat(Animal): pass
對Dog來說,Animal就是它的父類,對Animal來說,Dog就是它的子類別。 Cat和Dog類似。
繼承有什麼好處呢?最大的好處就是子類別獲得了父類別的全部功能。由於Animal實現了run()方法,因此,Dog和Cat作為它的子類,什麼事也沒幹,就自動擁有了run()方法:
dog = Dog() dog.run() cat = Cat() cat.run()
Animal is running... Animal is running...
當然,也可以對子類增加一些方法,比如Dog類。
繼承的第二個好處需要我們對程式碼做一點改進。你看到了,無論是Dog還是Cat,它們run()的時候,顯示的都是Animal is running...,符合邏輯的做法是分別顯示Dog is running...和Cat is running... ,因此,對Dog和Cat類別改進如下:
class Animal(object): def run(self): print('Animal is running...')class Dog(Animal): def run(self): print('Dog is haha running...') def eat(self): print('Eating meat...') class Cat(Animal): def run(self): print('Cat is miaomiao running...') def eat(self): print('Eating fish...')dog = Dog() dog.run() dog.eat() cat = Cat() cat.run() cat.eat()
再次运行,结果如下:
Dog is haha running... Eating meat... Cat is miaomiao running... Eating fish...
當子類別和父類別都存在相同的run()方法時,我們說,子類別的run()覆蓋了父類別的run (),在程式碼運行的時候,總是會呼叫子類別的run()。這樣,我們就獲得了繼承的另一個好處:多型態。
要理解什麼是多態,我們要先對資料型別再作一點說明。當我們定義一個class的時候,我們其實就定義了一種資料型別。我們定義的資料類型和Python自帶的資料類型,例如str、list、dict沒什麼兩樣:
a = list()#a是list类型#a是list类型 b = Animal() #b是Animal类型 c = Dog #c是Dog类型
判斷一個變數是否是某個類型可以用isinstance()判斷:
>>> isinstance(a, list) True >>> isinstance(b, Animal) True >>> isinstance(c, Dog) True
看來a,b,c確實對應著list、Animal、Dog這3種類型。
但等等,試試看:
>>> isinstance(c, Animal) True
看來c不只是Dog,c還是Animal!
不過仔細想想,這是有道理的,因為Dog是從Animal繼承下來的,當我們創建了一個Dog的實例c時,我們認為c的資料型別是Dog沒錯。但c同時也是Animal也沒錯,Dog本來就是Animal的一種!
所以,在繼承關係中,如果一個實例的資料型別是某個子類,那麼它的資料型別也可以被看做父類。但是,反過來就不行:
>>> b = Animal() >>> isinstance(b, Dog) False
Dog可以看成Animal,但Animal不可以看成Dog。
要理解多型態的好處,我們還需要再寫一個函數,這個函數接受一個Animal型別的變數:
def run_twice(animal): animal.run() animal.run()
當我們傳入Animal的實例時,run_twice()就列印出:
>>> run_twice(Animal()) Animal is running... Animal is running...
當我們傳入Dog的實例時,run_twice()就列印出:
>>> run_twice(Dog()) Dog is running... Dog is running...
看上去沒啥意思,但是仔細想想,如果我們再定義一個pig類型,也從Animal派生:
class Pig(Animal): def run(self): print('Pig is running slowly...')
當我們呼叫run_twice(pig())
>>> run_twice(Pig()) Pig is running slowly... Pig is running slowly...
多態的好處就是,當我們需要傳入Dog、Cat、Pig時,我們只需要接收Animal類型就可以了,因為Dog、Cat、Pig都是Animal類型,然後,按照Animal類型進行操作即可。由於Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類別或子類,就會自動呼叫實際類型的run()方法,這是多態的意思:
對於一個變量,我們只需要知道它是Animal類型,無需確切地知道它的子類型,就可以放心地調用run()方法,而具體調用run()方法是作用在Animal、Dog、cat、還是Pig物件上的,由運行時該物件的確切類型決定,這就是多態真正的威力:調用方只管調用,不管細節,而當我們新增一種Animal的子類別時,只要確保run()方法編寫正確,不用管原來的程式碼是如何呼叫的。這就是著名的「開閉」原則:
對修改封閉:不需要修改依賴Animal類型的run_twice()等函數。
繼承還可以一級一級繼承下來。而任何類,最終都可以追溯到根類object,這些繼承關係看起來就像一顆倒著的樹:
相關推薦:
以上是Python物件導向之繼承與多態性的詳細內容。更多資訊請關注PHP中文網其他相關文章!