首頁  >  文章  >  後端開發  >  Python物件導向之繼承與多態性

Python物件導向之繼承與多態性

不言
不言原創
2018-04-14 10:24:191707瀏覽

本篇文章給大家分享的內容是關於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物件導向之存取限制

Python物件導向之類與實例















#### ##############

以上是Python物件導向之繼承與多態性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn