要理解什么是多態(tài),我們首先要對(duì)數(shù)據(jù)類型再作一點(diǎn)說(shuō)明。當(dāng)我們定義一個(gè)class的時(shí)候,我們實(shí)際上就定義了一種數(shù)據(jù)類型。我們定義的數(shù)據(jù)類型和Python自帶的數(shù)據(jù)類型,比如str、list、dict沒什么兩樣: a = list() # a是list類型 b = Animal() # b是Animal類型 c = Dog() # c是Dog類型 判斷一個(gè)變量是否是某個(gè)類型可以用isinstance()判斷: >>> isinstance(a, list) True >>> isinstance(b, Animal) True >>> isinstance(c, Dog) True 看來(lái)a、b、c確實(shí)對(duì)應(yīng)著list、Animal、Dog這3種類型。 但是等等,試試: >>> isinstance(c, Animal) True 看來(lái)c不僅僅是Dog,c還是Animal! 不過仔細(xì)想想,這是有道理的,因?yàn)镈og是從Animal繼承下來(lái)的,當(dāng)我們創(chuàng)建了一個(gè)Dog的實(shí)例c時(shí),我們認(rèn)為c的數(shù)據(jù)類型是Dog沒錯(cuò),但c同時(shí)也是Animal也沒錯(cuò),Dog本來(lái)就是Animal的一種! 所以,在繼承關(guān)系中,如果一個(gè)實(shí)例的數(shù)據(jù)類型是某個(gè)子類,那它的數(shù)據(jù)類型也可以被看做是父類。但是,反過來(lái)就不行: >>> b = Animal() >>> isinstance(b, Dog) False Dog可以看成Animal,但Animal不可以看成Dog。 要理解多態(tài)的好處,我們還需要再編寫一個(gè)函數(shù),這個(gè)函數(shù)接受一個(gè)Animal類型的變量: def run_twice(animal): animal.run() animal.run() 當(dāng)我們傳入Animal的實(shí)例時(shí),run_twice()就打印出: >>> run_twice(Animal()) Animal is running... Animal is running... 當(dāng)我們傳入Dog的實(shí)例時(shí),run_twice()就打印出: >>> run_twice(Dog()) Dog is running... Dog is running... 當(dāng)我們傳入Cat的實(shí)例時(shí),run_twice()就打印出: >>> run_twice(Cat()) Cat is running... Cat is running... 看上去沒啥意思,但是仔細(xì)想想,現(xiàn)在,如果我們?cè)俣x一個(gè)Tortoise類型,也從Animal派生: class Tortoise(Animal): def run(self): print('Tortoise is running slowly...') 當(dāng)我們調(diào)用run_twice()時(shí),傳入Tortoise的實(shí)例: >>> run_twice(Tortoise()) Tortoise is running slowly... Tortoise is running slowly... 你會(huì)發(fā)現(xiàn),新增一個(gè)Animal的子類,不必對(duì)run_twice()做任何修改,實(shí)際上,任何依賴Animal作為參數(shù)的函數(shù)或者方法都可以不加修改地正常運(yùn)行,原因就在于多態(tài)。 多態(tài)的好處就是,當(dāng)我們需要傳入Dog、Cat、Tortoise……時(shí),我們只需要接收Animal類型就可以了,因?yàn)镈og、Cat、Tortoise……都是Animal類型,然后,按照Animal類型進(jìn)行操作即可。由于Animal類型有run()方法,因此,傳入的任意類型,只要是Animal類或者子類,就會(huì)自動(dòng)調(diào)用實(shí)際類型的run()方法,這就是多態(tài)的意思: 對(duì)于一個(gè)變量,我們只需要知道它是Animal類型,無(wú)需確切地知道它的子類型,就可以放心地調(diào)用run()方法,而具體調(diào)用的run()方法是作用在Animal、Dog、Cat還是Tortoise對(duì)象上,由運(yùn)行時(shí)該對(duì)象的確切類型決定,這就是多態(tài)真正的威力:調(diào)用方只管調(diào)用,不管細(xì)節(jié),而當(dāng)我們新增一種Animal的子類時(shí),只要確保run()方法編寫正確,不用管原來(lái)的代碼是如何調(diào)用的。這就是著名的“開閉”原則: 對(duì)擴(kuò)展開放:允許新增Animal子類; 對(duì)修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。 繼承還可以一級(jí)一級(jí)地繼承下來(lái),就好比從爺爺?shù)桨职?、再到兒子這樣的關(guān)系。而任何類,最終都可以追溯到根類object,這些繼承關(guān)系看上去就像一顆倒著的樹。比如如下的繼承樹: ┌───────────────┐ │ object │ └───────────────┘ │ ┌────────────┴────────────┐ │ │ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ Animal │ │ Plant │ └─────────────┘ └─────────────┘ │ │ ┌─────┴──────┐ ┌─────┴──────┐ │ │ │ │ ▼ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Dog │ │ Cat │ │ Tree │ │ Flower │ 分享知識(shí),分享快樂!希望中國(guó)站在編程之巔!
360圖書館館號(hào):rsgz002.360doc.com |
|