Python 多繼承中的一個詭異現(xiàn)象 既是 Father又是grandfather
我們知道,在面向?qū)ο缶幊汤锩妫?繼承 是一個很重要的概念。子類可以使用父類的方法和屬性。
例如下面這段代碼:
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)
運行效果如下圖所示:
從圖中可以看到,子類并沒有 self.address
這個屬性,但是當(dāng)我們直接打印的時候,并不會報錯,它會自動使用父類的 address
屬性。
顯然,如果一個屬性,子類也沒有,父類也沒有,那肯定會報錯,如下圖所示:
我們也知道,Python
是支持多繼承的,一個子類可以有多個父類。那么,大家請看下面這段代碼:
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()
運行效果如下圖所示:
大家仔細觀察,會發(fā)現(xiàn)這段代碼有點奇怪。我調(diào)用的是 son.where()
方法,由于 Son 類沒有這個方法,于是它會去它的兩個父類里面找。于是在 Father 這個父類里面找到了。于是執(zhí)行 Father 里面的 where()
方法,目前為止沒有問題。
但接下來就不對了, .where()
方法里面,調(diào)用了 self.address
屬性??蓡栴}是 Father
這個類它并沒有 .address 屬性啊!而且 Father
也沒有父類,那么這個 .address
屬性是從哪里來的?
難道說,在開發(fā)者不知道的隱秘的角落里面, GrandFather
類悄悄成為了 Father
的父類?這樣一來, GrandFather
豈不是又是 C 的父類,又是 C 的父類的父類? GrandFather
既是爸爸又是爺爺?
實際上,并不存在這么混亂的關(guān)系。要解釋這個現(xiàn)象,我們就要從 self
這個東西說起。
我們知道,類的屬性都是以 self
開頭,方法的第一個參數(shù)也是 self
。那么這個 self 到底是什么東西?我們用一段小代碼來看看它是什么東西:
class A: def get_self(self): return self test = A() what_is_self = test.get_self() test is what_is_self
運行效果如下圖所示:
從圖里面可以看到, self
實際上就是這個類的實例。我們再來看有繼承的情況:
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
,但這個 self
實際上是 B 類的實例。因為我自始至終就只初始化了 B 類,并沒有初始化 A 類。A 雖然是 B 類的父類。但父類的 self
都會變成子類的實例。
明白這一點以后,前面的問題就很好解釋了,我們多打印一些信息:
大家注意畫紅線的地方, self
始終都是 Son 類的實例。所以,一開始初始化 .address
的時候,就是初始化的 Son 的實例的 .address
屬性。后面在 .where
里面調(diào)用 .address
的時候,也是讀取的 Son
的實例的 .address
屬性。所以,并不存在 Father
類去讀 GrandFather
類的情況。自始至終,都是 Son 類的實例在進行各種操作。
所以,在這個例子里面,當(dāng)使用了繼承以后,所有父類的屬性和方法,子類如果有相同的名字,那么以子類的為準(zhǔn)。如果子類沒有定義,那么父類的屬性和方法,其實都會跑到子類里面去。 所有看起來是父類進行的操作,其實都是子類在進行 。上面的代碼,甚至可以近似等價于:
由于 say
方法在子類中有了定義,所以子類覆蓋父類。以子類的 say 方法為準(zhǔn)。 where
和 address
由于子類沒有定義,所以 Father
類的 where
方法和 GrandFather
里面的 address
屬性,都會直接 跑 到子類里面。
到此這篇關(guān)于Python 多繼承中的一個詭異現(xiàn)象 既是 Father又是grandfather的文章就介紹到這了,更多相關(guān)Python 多繼承中的一個詭異現(xiàn)象 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PyTorch變分自編碼器的構(gòu)建與應(yīng)用小結(jié)
變分自編碼器是一種強大的深度學(xué)習(xí)模型,用于學(xué)習(xí)數(shù)據(jù)的潛在表示并能生成新的數(shù)據(jù)點,使用PyTorch實現(xiàn)VAE不僅可以加深對生成模型的理解,還可以利用其靈活性進行各種實驗,這篇文章主要介紹了PyTorch變分自編碼器的構(gòu)建與應(yīng)用,需要的朋友可以參考下2024-07-07Linux添加Python?path方法及修改環(huán)境變量的三種方法
這篇文章主要介紹了Linux添加Python?path方法及修改環(huán)境變量的三種方法,Linux 下設(shè)置環(huán)境變量有三種方法,一種用于當(dāng)前終端,一種用于當(dāng)前用戶,一種用于所有用戶,本文對每種方法給大家介紹的非常詳細,需要的朋友可以參考下2022-07-07