新聞中心
我們知道,在面向?qū)ο缶幊汤锩?,繼承是一個(gè)很重要的概念。子類可以使用父類的方法和屬性。例如下面這段代碼:

成都創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站、網(wǎng)站重做改版、師宗網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5建站、商城網(wǎng)站定制開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為師宗等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
- class Father:
- def __init__(self):
- self.address = '上海'
- def say(self):
- print('我是爸爸')
- class Son(Father):
- def __init__(self):
- super().__init__()
- def say(self):
- print('我是兒子')
- son = Son()
- print(son.address)
運(yùn)行效果如下圖所示:
從圖中可以看到,子類并沒有self.address這個(gè)屬性,但是當(dāng)我們直接打印的時(shí)候,并不會(huì)報(bào)錯(cuò),它會(huì)自動(dòng)使用父類的address屬性。
顯然,如果一個(gè)屬性,子類也沒有,父類也沒有,那肯定會(huì)報(bào)錯(cuò),如下圖所示:
我們也知道,Python 是支持多繼承的,一個(gè)子類可以有多個(gè)父類。那么,大家請(qǐng)看下面這段代碼:
- class GrandFather:
- def __init__(self):
- self.address = '上海'
- def say(self):
- print('我是爸爸')
- class Father:
- def __init__(self):
- self.age = 100
- def where(self):
- print('我現(xiàn)在住在:', self.address)
- class Son(GrandFather, Father):
- def __init__(self):
- super().__init__()
- def say(self):
- print('我是兒子')
- son = Son()
- son.where()
運(yùn)行效果如下圖所示:
大家仔細(xì)觀察,會(huì)發(fā)現(xiàn)這段代碼有點(diǎn)奇怪。我調(diào)用的是son.where()方法,由于Son類沒有這個(gè)方法,于是它會(huì)去它的兩個(gè)父類里面找。于是在Father這個(gè)父類里面找到了。于是執(zhí)行Father里面的where()方法,目前為止沒有問題。
但接下來就不對(duì)了,.where()方法里面,調(diào)用了self.address屬性。可問題是Father這個(gè)類它并沒有.address屬性啊!而且Father也沒有父類,那么這個(gè).address屬性是從哪里來的?
難道說,在開發(fā)者不知道的隱秘的角落里面,GrandFather 類悄悄成為了Father的父類?這樣一來,GrandFather豈不是又是 C 的父類,又是 C 的父類的父類?GrandFather既是爸爸又是爺爺?
實(shí)際上,并不存在這么混亂的關(guān)系。要解釋這個(gè)現(xiàn)象,我們就要從self這個(gè)東西說起。
我們知道,類的屬性都是以self開頭,方法的第一個(gè)參數(shù)也是self。那么這個(gè) self 到底是什么東西?我們用一段小代碼來看看它是什么東西:
- class A:
- def get_self(self):
- return self
- test = A()
- what_is_self = test.get_self()
- test is what_is_self
運(yùn)行效果如下圖所示:
從圖里面可以看到,self實(shí)際上就是這個(gè)類的實(shí)例。我們?cè)賮砜从欣^承的情況:
- class A:
- def get_self(self):
- return self
- class B(A):
- def __init__(self):
- ...
- test = B()
- what_is_self = test.get_self()
- print(what_is_self)
從圖中可以看到,雖然我在 A 類的.get_self()方法中返回了self,但這個(gè)self實(shí)際上是 B 類的實(shí)例。因?yàn)槲易允贾两K就只初始化了 B 類,并沒有初始化 A 類。A 雖然是 B 類的父類。但父類的 self 都會(huì)變成子類的實(shí)例。
明白這一點(diǎn)以后,前面的問題就很好解釋了,我們多打印一些信息:
大家注意畫紅線的地方,self始終都是Son類的實(shí)例。所以,一開始初始化.address的時(shí)候,就是初始化的Son的實(shí)例的.address屬性。后面在.where里面調(diào)用.address的時(shí)候,也是讀取的Son的實(shí)例的.address屬性。所以,并不存在Father類去讀GrandFather類的情況。自始至終,都是Son類的實(shí)例在進(jìn)行各種操作。
所以,在這個(gè)例子里面,當(dāng)使用了繼承以后,所有父類的屬性和方法,子類如果有相同的名字,那么以子類的為準(zhǔn)。如果子類沒有定義,那么父類的屬性和方法,其實(shí)都會(huì)跑到子類里面去。所有看起來是父類進(jìn)行的操作,其實(shí)都是子類在進(jìn)行。上面的代碼,甚至可以近似等價(jià)于:
由于say方法在子類中有了定義,所以子類覆蓋父類。以子類的say方法為準(zhǔn)。where和address由于子類沒有定義,所以Father類的where方法和GrandFather里面的address屬性,都會(huì)直接跑到子類里面。
網(wǎng)站題目:既是爸爸又是爺爺?Python多繼承中的一個(gè)詭異現(xiàn)象
URL鏈接:http://fisionsoft.com.cn/article/cddpogd.html


咨詢
建站咨詢
