Python入門系列22 - 面向?qū)ο?四)
Python入門系列22

面向?qū)ο????(四)
本篇文字約為2500字,閱讀時(shí)間約為10分鐘。
1
前言
本節(jié)介紹面向?qū)ο蟮摹袄^承”特性,這將是面向?qū)ο笃詈蟮幕A(chǔ)部分,隨后我會(huì)畫出一個(gè)思維導(dǎo)圖來總結(jié)下這一個(gè)月以來面向?qū)ο笤O(shè)計(jì)到的知識(shí)點(diǎn)。
面向?qū)ο蟮娜筇卣鞣謩e為:封裝、繼承、多態(tài)。封裝實(shí)際上就是上次講的私有化,但是封裝是一種思想,它所涉及的東西非常廣,后續(xù)在慢慢補(bǔ)充,忘記的可以看下上次的總結(jié)。Python入門系列21 - 面向?qū)ο?三)
而多態(tài)打算作為后續(xù)的進(jìn)階知識(shí)點(diǎn)來介紹。所以基礎(chǔ)部分到繼承就會(huì)將面向?qū)ο笞鳛橐粋€(gè)完結(jié)。廢話不多說了,進(jìn)入正題吧。
2
繼承
何謂繼承?在現(xiàn)實(shí)世界,比如爸爸到了一定年齡終歸要留下一筆財(cái)富,而此時(shí)的財(cái)富一般就由兒子來繼承。這樣一來原來屬于爸爸的錢,兒子在繼承這筆財(cái)富之后,便有了使用權(quán)。所以這里兒子是子類,爸爸是父類。
而映射到計(jì)算機(jī)中也是一個(gè)道理,可以想象之前的python面向?qū)ο蟮恼鹿?jié)中,我一直以女朋友作為例子來進(jìn)行講解,這里女朋友再往上抽象一層得到的是什么呢?女朋友可以歸為人類這一范疇。所以我們可以說女朋友繼承了人的基本特性,人都有名字,性別,年齡的屬性,來看下女朋友的類是如何繼承人的類去實(shí)現(xiàn)的:
父類(人類):
class?Human(object):
????"""人的初始化方法,傳入名稱和年齡"""
????def?__init__(self,?name,?age):
????????self.name?=?name
????????self.age?=?age
????def?say(self):
????????print(f'人的名字:{self.name}')
????????print(f'人的年齡:{self.age}')
????def?eat(self):
????????print('This?\'s?Human?eat?method!')
可以看到,上面的代碼中將女票的姓名與年齡提到了人的初始化方法中,再來看下女票類的代碼:
from?toobject.python22?import?Human
class?GirlFriend(Human):
????#?交過的女朋友個(gè)數(shù)
????total_nums?=?0
????#?初始化構(gòu)造方法
????def?__init__(self,?name,?age,?weight):
????????self.weight?=?weight
????#?行為,說出自己的特征
????def?eat(self):
????????print('Here?\'s?girlFriend?eat?method')
girlFriend?=?GirlFriend('女兒國公主',?18,?90)
girlFriend.say()
可以看到?GirlFriend(Human): 通過這樣的形式來實(shí)現(xiàn)所謂的繼承,調(diào)用時(shí),我們可以直接調(diào)用父類的say()方法,來看下能否直接調(diào)用。

報(bào)錯(cuò)了,可以看到英文大致意思是說女朋友這個(gè)類并沒有name的屬性!為什么呢?可以思考下,我們通過子類直接調(diào)用父類的方法,然后報(bào)錯(cuò)信息出現(xiàn)在了父類的代碼上。
實(shí)際上因?yàn)槲覀冊谡{(diào)用女朋友類的時(shí)候,沒有將name、age屬性向父類進(jìn)行傳遞,所以在父類中的name、age屬性是空的,所以會(huì)在打印時(shí)發(fā)生報(bào)錯(cuò)!
3
繼承調(diào)用父類
原因既然知道了,那么一切都好說了,我們現(xiàn)在只需要在女朋友初始方法中調(diào)用人的初始方法,并將name、age參數(shù)傳遞到后面,即可實(shí)現(xiàn)調(diào)用父類的say()方法,來看下代碼:
from?toobject.python22?import?Human
class?GirlFriend(Human):
????#?交過的女朋友個(gè)數(shù)
????total_nums?=?0
????#?初始化構(gòu)造方法
????def?__init__(self,?name,?age,?weight):
????????Human.__init__(self,?name,?age)
????????self.weight?=?weight
????#?行為,說出自己的特征
????def?eat(self):
????????print('Here?\'s?girlFriend?eat?method')
girlFriend?=?GirlFriend('女兒國公主',?18,?90)
girlFriend.say()
print(girlFriend.age)
print(girlFriend.name)

通過?Human.__init__(self,?name,?age)將外面的參數(shù)傳入到父類中,成功調(diào)用了父類的方法以及屬性,也就是人中的姓名和年齡,以及說話的方法。
4
繼承中的super關(guān)鍵詞
上面的寫法大家可以想一想有沒有什么問題呢?雖然確實(shí)可以通過用父類的類名來直接調(diào)用__init__方法進(jìn)行初始化,而這種特性在之前的面向?qū)ο笮≌n堂中也講過,直接用類.方法是python這門語言的一種特性!忘記的話可以回顧:python小課堂19 - 面向?qū)ο笃ǘ?/a>
假設(shè)后續(xù)我們要修改女朋友所繼承的父類,不讓她繼承人類了,原本女兒國國王就是妖怪的化身!所以讓她繼承妖怪類好了....~
那么此時(shí)我們就需要改兩個(gè)地方了,如下圖:

要知道一點(diǎn),寫程序其實(shí)有一個(gè)本質(zhì),就是如果有改動(dòng)的地方,盡量讓自己寫出的代碼在原有的基礎(chǔ)上進(jìn)行最少的修改!這點(diǎn)也就是設(shè)計(jì)模式常說的開閉原則(聽不懂的話忽略即可,有好奇心的寶寶可以去查查看咯...)
所以為了遵循以上的原則,我們將原有程序進(jìn)行改裝,就要用到標(biāo)題4所說的super關(guān)鍵字了!super:超級(jí)的意思,因?yàn)橛行┱Z言中父類也叫超類,所以估計(jì)才會(huì)用super來作為調(diào)用父類的關(guān)鍵詞吧,個(gè)人猜測.....接下來看下如何進(jìn)行調(diào)用呢?
from?toobject.python22?import?Human
from?toobject.python22?import?Human
class?GirlFriend(Human):
????#?交過的女朋友個(gè)數(shù)
????total_nums?=?0
????#?初始化構(gòu)造方法
????def?__init__(self,?name,?age,?weight):
????????super(GirlFriend,?self).__init__(name,?age)
????????self.weight?=?weight
????#?行為,說出自己的特征
????def?eat(self):
????????print('Here?\'s?girlFriend?eat?method')
girlFriend?=?GirlFriend('女兒國公主',?18,?90)
girlFriend.say()
print(girlFriend.age)
print(girlFriend.name)

通過?super(GirlFriend,?self).__init__(name,?age) 的調(diào)用方式,將子類以及self傳入到super里,在調(diào)用父類的構(gòu)造方法將參數(shù)傳入即可!
仔細(xì)思考下,這樣一來,我們?nèi)绻淖兞死^承類,將女朋友的父類改為妖怪....那么只需要在class聲明的小括號(hào)后修改就能達(dá)到目的了,同時(shí)實(shí)現(xiàn)了代碼的最小改動(dòng)!
5
繼承中的重寫
心細(xì)的同學(xué)在上面的子父類中發(fā)現(xiàn)了一個(gè)相同點(diǎn),沒錯(cuò),就是它們都共同有一個(gè)名為eat()的方法函數(shù)。如果我此時(shí)用實(shí)例對(duì)象去調(diào)用eat(),你們猜會(huì)打印輸出什么?
from?toobject.python22?import?Human
class?GirlFriend(Human):
????#?交過的女朋友個(gè)數(shù)
????total_nums?=?0
????#?初始化構(gòu)造方法
????def?__init__(self,?name,?age,?weight):
????????super(GirlFriend,?self).__init__(name,?age)
????????self.weight?=?weight
????#?吃
????def?eat(self):
????????print('Here?\'s?girlFriend?eat?method')
girlFriend?=?GirlFriend('女兒國公主',?18,?90)
girlFriend.eat()

輸出了子類eat()方法中的調(diào)用,說明了子類把父類的eat()覆蓋掉了,說專業(yè)點(diǎn)就是傳說中的重寫!? 那么問題來了,為什么會(huì)有重寫呢?重寫的好處是什么呢?
必然是擴(kuò)展性與復(fù)用性!大家可以想想,女朋友繼承了人類的特征,會(huì)吃!所以到具體類中,讓“吃”具體化,女票有著一套自己吃東西的體系!
若既想保留人類的吃方法,又要凸顯女朋友吃法的個(gè)性,那該如何是好呢?這點(diǎn)就利用了super關(guān)鍵字去解決了.....!
from?toobject.python22?import?Human
class?GirlFriend(Human):
????#?交過的女朋友個(gè)數(shù)
????total_nums?=?0
????#?初始化構(gòu)造方法
????def?__init__(self,?name,?age,?weight):
????????super(GirlFriend,?self).__init__(name,?age)
????????self.weight?=?weight
????#?吃
????def?eat(self):
????????super(GirlFriend,self).eat()
????????print('Here?\'s?girlFriend?eat?method')
girlFriend?=?GirlFriend('女兒國公主',?18,?90)
girlFriend.eat()

可以看到都輸出了.....
6
總結(jié)
總結(jié)一下,python的繼承跟別的語言不太一樣,比如Java類的繼承,只能單繼承,而Python不一樣,Python自身可以多繼承,也就是繼承多個(gè)類,這點(diǎn)放到后面講,因?yàn)槭沁M(jìn)階的知識(shí)點(diǎn)。
到這里,我就將面向?qū)ο笏械幕A(chǔ)點(diǎn)講完了.....來用思維導(dǎo)圖做個(gè)總結(jié)吧!基礎(chǔ)歸基礎(chǔ),后續(xù)還有面向?qū)ο蟮倪M(jìn)階部分,敬請(qǐng)期待......思維導(dǎo)圖如下:

至此完!
