Python-類的繼承

目錄:http://www.reibang.com/p/863c446364a8

類的繼承

談類的繼承之前我們要知道:

面向?qū)ο蟮娜筇匦裕悍庋b来候、繼承、多態(tài)

接下來我們就來學習類的繼承唱遭。

一舞吭、什么是類的繼承产喉?

繼承:顧名思義子承父業(yè),合法繼承家產(chǎn)贝椿,就是如果你是獨生子想括,而且你也很孝順,不出意外烙博,你會繼承你父母所有家產(chǎn)瑟蜈,他們的所有財產(chǎn)都會由你使用。

類的繼承:專業(yè)角度來說B繼承A類 B叫做A的子類又稱派生類渣窜,A叫做B的父類铺根,又稱基類或超類。B類以及B的對象使用A類的所有的屬性以及方法乔宿。

那么我們來舉一個最簡單的例子位迂。如果我們想要寫三個類,通常我們的寫法是這樣的。

class Person:

? ? def __init__(self,name,sex,age):

? ? ? ? self.name = name

? ? ? ? self.age = age

? ? ? ? self.sex = sex

class Cat:

? ? def __init__(self,name,sex,age):

? ? ? ? self.name = name

? ? ? ? self.age = age

? ? ? ? self.sex = sex

class Dog:

? ? def __init__(self,name,sex,age):

? ? ? ? self.name = name

? ? ? ? self.age = age

? ? ? ? self.sex = sex

通過上邊的例子可以看出我們定義了三個類掂林,且方法以及方法的屬性都相同臣缀。那么我們用繼承實現(xiàn)同樣的效果。

class Animal:

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex


class Person(Animal):? ##括號里為繼承也是父類

? ? pass

class Dog(Animal):

? ? pass

class Cat(Animal):

? ? pass

通過上邊的繼承我們可以看出繼承的優(yōu)點:

1泻帮、節(jié)省代碼

2精置、增強了耦合性

3、使代碼更加規(guī)范化

二锣杂、繼承的分類

就向上面的例子:

Aminal 叫做父類,基類,超類脂倦。

Person Cat Dog: 子類,派生類蹲堂。

繼承:可以分單繼承狼讨,多繼承

三、單繼承

1柒竞、子類以及對象可以調(diào)用父類的屬性及方法政供。

class Animal:

? ? live="有生命的"

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex

? ? def eat(self):

? ? ? ? print("動物都需要進食")


class Person(Animal):##括號里為繼承,父類

????pass


## 1朽基、從類名執(zhí)行父類的屬性

print(Person.live)

Person.eat(55)

運行結(jié)果:

有生命的

人類都需要進食


## 2布隔、從對象執(zhí)行父類一切

(1) 實例化對象時一定會執(zhí)行三件事,一定會執(zhí)行__init__

p1=Person("LiMing",20,"男")

print(p1.__dict__)

運行結(jié)果:

{'name': 'LiMing', 'age': 20, 'sex': '男'}


(2)對象執(zhí)行類的父類的屬性稼虎,方法衅檀。

p1=Person("LiMing",20,"男")

print(p1.live)

p1.eat()

運行結(jié)果:

有生命的

動物都需要進食

(3)對象空間重寫繼承父類的方法

p1.eat="LiMing"

print(p1.eat)

運行結(jié)果:

LiMing

#注:這里修改的是p1對象空間,不是父類的方法霎俩。

子類以及子類的對象只能調(diào)用父類的屬性以及方法哀军,不能操作(增刪改)

2、對象執(zhí)行順序

class Animal:

? ? live="有生命的"

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex

? ? def eat(self):

? ? ? ? print("動物都需要進食")


class Person(Animal):##括號里為繼承打却,父類

????def eat(self):

? ? ? ? print("人類都需要進食")

p1=Person("LiMing",20,"男")

p1.eat()

運行結(jié)果:

人類都需要進食

總結(jié):對象查找順序:從對象空間找名字杉适,子類找名字,父類找名字

3柳击、?如何既要執(zhí)行父類方法又要執(zhí)行子類方法

方法一:如果想執(zhí)行父類的方法猿推,這個方法與子類方法一起用,那么就在子類的方法中寫上:

父類.__init__(對象,其他參數(shù))

比如:

class Animal:

? ? live="有生命的"

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex

? ? def eat(self):

? ? ? ? print("動物都需要進食")

class Person(Animal):##括號里為繼承捌肴,父類

? ? def __init__(self,name,age,sex,hobby):

? ? ? ? Animal.__init__(self,name,age,sex)

? ? ? ? self.hobby=hobby

? ? def eat(self):

? ? ? ? print("人類都需要進食")

p1=Person("LiMing",20,"男","看書")

print(p1.__dict__)

運行結(jié)果:

{'name': 'LiMing', 'age': 20, 'sex': '男', 'hobby': '看書'}

方法二:利用super(子類類名蹬叭,self(這里的參數(shù)可以不寫)).__init__(參數(shù))

比如:

class Animal:

? ? live="有生命的"

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex

? ? def eat(self):

? ? ? ? print("動物都需要進食")

class Person(Animal):##括號里為繼承,父類

? ? def __init__(self,name,age,sex,hobby):

? ? ? ? super(Person,self).__init__(name,age,sex)

? ? ? ? self.hobby=hobby

? ? def eat(self):

? ? ? ? print("人類都需要進食")


p1=Person("LiMing",20,"男","看書")

print(p1.__dict__)

運行結(jié)果:

{'name': 'LiMing', 'age': 20, 'sex': '男', 'hobby': '看書'}

舉一反三状知,我們執(zhí)行子類與父類的eat方法

class Animal:

? ? live="有生命的"

? ? def __init__(self,name,age,sex):

? ? ? ? self.name=name

? ? ? ? self.age=age

? ? ? ? self.sex=sex

? ? def eat(self):

? ? ? ? print("動物都需要進食")

class Person(Animal):##括號里為繼承秽五,父類

? ? def __init__(self,hobby):

? ? ? ? self.hobby=hobby

? ? def eat(self):

? ? ? ? print("人類都需要進食")

? ? ? ? super().eat()

p1=Person("看書")

p1.eat()

運行結(jié)果:

人類都需要進食

動物都需要進食

接著我們做幾道單繼承練習題。

1试幽、

class Base:

? ? def __init__(self, num):

? ? ? ? self.num = num

? ? def func1(self):

? ? ? ? print(self.num)

class Foo(Base):

? ? pass

obj = Foo(123)? ? #實例化對象筝蚕,創(chuàng)建對象空間obj,自動執(zhí)行__init__方法卦碾,將123傳給self

obj.func1()? ? ? ? # 123 對象的調(diào)用,執(zhí)行Base中的func1

運行結(jié)果

123

2起宽、

class Base:

? ? def __init__(self, num):

? ? ? ? self.num = num

? ? def func1(self):

? ? ? ? print(self.num)

class Foo(Base):

? ? def func1(self):

? ? ? ? print("Foo. func1", self.num)

obj = Foo(123)

obj.func1()? ? ? ? #根據(jù)對象執(zhí)行順序洲胖,先找---->對象空間------>子類------>父類,所以對象調(diào)用func1坯沪,? ? 子類與父類都有func1時先找子類

運行結(jié)果:

Foo. func1 123

3

class Base:

? ? def __init__(self, num):

? ? ? ? self.num = num

? ? def func1(self):

? ? ? ? print(self.num)

? ? ? ? self.func2()? ? #self----->obj #對象查詢空間绿映,此時的func2應該是子類中的func2,符合執(zhí)行順序

? ? def func2(self):

? ? ? ? print("Base.func2")

class Foo(Base):

? ? def func2(self):

? ? ? ? print("Foo.func2")

obj = Foo(123)

obj.func1()? ? ? ? ? ?# func1是Base中的 func2是?類中的

運行結(jié)果:

123

Foo.func2

4

class Base:

? ? def __init__(self, num):

? ? ? ? self.num = num

? ? def func1(self):

? ? ? ? print(self.num)

? ? ? ? self.func2()

? ? def func2(self):

? ? ? ? print(111, self.num)

class Foo(Base):

? ? def func2(self):

? ? ? ? print(222, self.num)

lst = [Base(1), Base(2), Foo(3)]

for obj in lst:

obj.func1()? ? #調(diào)用父類時只執(zhí)行父類,調(diào)用子類時先執(zhí)行子類腐晾,在執(zhí)行父類

運行結(jié)果:

1

111 1

2

111 2

3

222 3

通過上邊的執(zhí)行過程叉弦,結(jié)果你都答對了嗎?

四、多繼承

談到多繼承我們先來一個案例進行了解吧藻糖!

class God:

? ? def __init__(self,name):

? ? ? ? self.name=name

? ? def fly(self):

? ? ? ? print("會飛")

? ? def climb(self):

? ? ? ? print("神仙累了也需要爬樹")

class Monkey:

? ? def __init__(self,sex):

? ? ? ?self.sex=sex

? ? def climb(self):

? ? ? ? print("爬樹")

class MonkeySun(God,Monkey):

? ? pass

sun=MonkeySun()

sun.climb()

運行結(jié)果:

神仙累了也需要爬樹

#上邊MonkeySun類繼承了God類以及Monkey類淹冰,MonkeySun自然就可以執(zhí)行這兩類中的方法,這就是簡單的多繼承巨柒。多繼承?起來簡單. 也很好理解. 但是多繼承中, 存在著這樣?個問題. 當兩個?類中出現(xiàn)了重名?法的時候. 這時該怎么辦呢? 這時就涉及到如何查找?類?法的這么?個問題.即MRO(method resolution order) 問題. 在python中這是?個很復雜的問題. 因為在不同的python版本中使?的是不同的算法來完成MRO的.

Python中類的種類

在python2x版本中存在兩種類.:

  ?個叫經(jīng)典類. 在python2.2之前. ?直使?的是經(jīng)典類. 經(jīng)典類在基類的根如果什么都不寫.

  ?個叫新式類. 在python2.2之后出現(xiàn)了新式類. 新式類的特點是基類的根是object類樱拴。

python3x版本中只有一種類:

python3中使?的都是新式類. 如果基類誰都不繼承. 那這個類會默認繼承 object。

也就是在大體上Python的類分為兩種:一種是基類的根不是object的經(jīng)典類洋满,一種是基類的根是object的新式類晶乔。

我們先說經(jīng)典類的MRO算法。

首先我們舉一個實例:

class A:

? ? pass

class B(A):

? ? pass

class C(A):

? ? pass

class D(B, C):

? ? pass

class E:

? ? pass

class F(D, E):

? ? pass

class G(F, D):

? ? pass

class H:

? ? pass

class Foo(H, G):

? ? pass

然后第一步我們先畫出他的MRO圖牺勾,來展示一下他各個類之間的關(guān)系:

經(jīng)典類-MRO圖

我們乍一看正罢,這個圖就像一棵樹一樣,而經(jīng)典類的MRO算法恰巧也是根據(jù)樹狀結(jié)構(gòu)推導的驻民。

經(jīng)典類的MRO算法就是用來遍歷樹狀結(jié)構(gòu)的深度優(yōu)先遍歷翻具,他的原理如下。

首先我們會從左向右依次查找節(jié)點回还,如果后面查找的節(jié)點在前面已經(jīng)查找過呛占,則忽略不計。

樹狀圖

現(xiàn)在我們有一個樹狀結(jié)構(gòu)如上懦趋,那么他的遍歷順序就是:

遍歷順序

現(xiàn)在讓我們回到我們實例的MRO圖,然后按照深度優(yōu)先遍歷規(guī)則疹味,他的順序應該是如下:

實例類的MRO:Foo-> H -> G -> F -> E -> D -> B -> A -> C


到這里仅叫,就有了一個問題,假如類A與類C中都有一個方法sum()糙捺,但是類C是繼承類A的诫咱,也就是說類C重寫了類A的方法。按照繼承層級洪灯,如果我們的FOO類使用sum()這個方法坎缭,應該使用的類C中重寫的sum()方法,而不是使用類A中原生的sum()方法。

這也就是Python2.2之前的一個詬病掏呼,Python3徹底改變了這種MRO算法坏快,使用了一種新的方法。

接著我們說新式類的MRO算法憎夷。

Python3使用的這種新的方法叫做MRO序列莽鸿。

這個序列在類被創(chuàng)建之時就計算出來了,他是創(chuàng)建類時的伴生物拾给。他的通用公式如下:

mro(Child(Base1祥得,Base2)) = [ Child ] +merge( mro(Base1), mro(Base2), [ Base1, Base2] )

(其中Child繼承自Base1, Base2)

只看通用公式太過枯燥,讓我們舉個實例看看:假設有類C蒋得,他繼承類A和類B级及。即 class C(A,B)

此時類C的序列是:

mro( C ) = mro( C(A,B) )

? ? ? ? ? ? ? = [C] + merge( mro(A) + mro[B] + [A,B] )

? ? ? ? ? ? ? = [C] + merge( [A] + [B] + [A,B] )

? ? ? ? ? ? ? = [C,A,B]

誒,這里就有一個問題了额衙,為什么是[C,A,B],而不是[C,B,A]呢饮焦,這就要說MRO序列的一個特性--表頭提取。

首先我們先了解兩個概念入偷,表頭追驴,表尾。

我們拿我們的MRO序列[C,A,B]來舉例疏之,C就是表頭殿雪,A,B就是表尾。

接著來說表頭提取锋爪。

我們在進行到[C] + merge( [A] + [B] + [A,B] ) 這一步時丙曙,加號右邊的計算規(guī)則是:

[A] + [B] + [A,B]

我們把這三個序列標位①,②其骄,③亏镰。

1.首先查看①的表頭A,然后去其他兩個序列中拯爽,查看A是否在表尾中索抓,如果在表尾中,則跳過①毯炮,去②中重復操作逼肯。

2.但是①的表頭A不在其他序列的表尾中,所以提出A桃煎,同時刪除其他序列中的A篮幢。

3.這是式子就變成了?[B],提取出來的序列是[A].

4.接著重復第一步操作为迈,直至式子清空三椿。這個式子的結(jié)果就是序列[A,B]

然后我們的式子就變成了[C] +?[A,B]缺菌,序列之間的加法就是連接操作,他們相加的結(jié)果就是:[C,A,B].

最后我們來舉一個實例:

class A:

? ? pass

class B(A):

? ? pass

class C(A):

? ? pass

class D(B, C):

? ? pass

class E:

? ? pass

class F(D, E):

? ? pass

class G(F, D):

? ? pass

class H:

? ? pass

class Foo(H, G):

? ? pass

實例代碼如上搜锰,MRO圖不再贅述伴郁。

根據(jù)上面的MRO序列算法得:

mro( FOO ) = mro( FOO(H,G) )

? ? ? ? ? ? ? ? ? ?= [FOO] + merge( mro(H) + mro[G] + [H,G] )

? ? ? ? ? ? ? ? ? ?= [FOO] + merge( [H] + MRO[G] + [H,G] )

? ? ? ? ? ? ? ? ? ?= [FOO] + merge( [H] + ?[G,F,D,B,C,A,E] + [H,G] )

? ? ? ? ? ? ? ? ? ?= [FOO,H] + merge([G,F,D,B,C,A,E]?+ [G] )

? ? ? ? ? ? ? ? ? ?= [FOO,H,G] + merge([F,D,B,C,A,E])

? ? ? ? ? ? ? ? ? ?=?[FOO,H,G,F,D,B,C,A,E]


此時,因為類G也是一個多重繼承類纽乱,所以要提出來單獨計算蛾绎。


mro( G ) = mro( G(F,D) )

? ? ? ? ? ? ? = [G] + merge( mro(F) + mro[D] + [F,D] )

? ? ? ? ? ? ? = [G] + merge(?[F,D,B,C,A,E] + [D,B,C,A] + [F,D] )

? ? ? ? ? ? ? = [G,F] + merge(?[D,B,C,A,E]?+?[D,B,C,A]?+ [D] )

? ? ? ? ? ? ? = [G,F,D] + merge(?[B,C,A,E]?+?[B,C,A]? )

? ? ? ? ? ? ? = [G,F,D,B,C,A,E]


同理,類F和類D也要進行單獨計算鸦列。

mro( F ) = mro( F(D,E) )

? ? ? ? ? ? ? = [F] + merge( mro(D) + mro[E] + [D,E] )

? ? ? ? ? ? ? = [F] + merge( [D,B,C,A] + [E] + [D,E] )

? ? ? ? ? ? ? = [F,D] + merge( [B,C,A] + [E] + [E] )

? ? ? ? ? ? ? = [F,D,B,C,A,E]


mro( D ) = mro( D(B,C) )

? ? ? ? ? ? ? = [D] + merge( mro(B) + mro[C] + [B,C] )

? ? ? ? ? ? ? = [D] + merge( [B,A] + [C,A] + [B,C] )

? ? ? ? ? ? ? = [D,B] +?merge( [A] + [C,A] + [C] )

? ? ? ? ? ? ? = [D,B,C] +?merge( [A] + [A] )

? ? ? ? ? ? ? = [D,B,C,A]

最后租冠,他的MRO順序為:[FOO,H,G,F,D,B,C,A,E]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市薯嗤,隨后出現(xiàn)的幾起案子顽爹,更是在濱河造成了極大的恐慌,老刑警劉巖骆姐,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镜粤,死亡現(xiàn)場離奇詭異,居然都是意外死亡玻褪,警方通過查閱死者的電腦和手機肉渴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來带射,“玉大人同规,你說我怎么就攤上這事】呱纾” “怎么了券勺?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灿里。 經(jīng)常有香客問我关炼,道長,這世上最難降的妖魔是什么匣吊? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任儒拂,我火速辦了婚禮,結(jié)果婚禮上色鸳,老公的妹妹穿的比我還像新娘侣灶。我一直安慰自己,他們只是感情好缕碎,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著池户,像睡著了一般咏雌。 火紅的嫁衣襯著肌膚如雪凡怎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天赊抖,我揣著相機與錄音统倒,去河邊找鬼。 笑死氛雪,一個胖子當著我的面吹牛房匆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播报亩,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼浴鸿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弦追?” 一聲冷哼從身側(cè)響起岳链,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劲件,沒想到半個月后掸哑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡零远,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年苗分,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牵辣。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡摔癣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出服猪,到底是詐尸還是另有隱情供填,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布罢猪,位于F島的核電站近她,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膳帕。R本人自食惡果不足惜粘捎,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望危彩。 院中可真熱鬧攒磨,春花似錦、人聲如沸汤徽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谒府。三九已至拼坎,卻和暖如春浮毯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泰鸡。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工债蓝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盛龄。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓饰迹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親余舶。 傳聞我的和親對象是個殘疾皇子啊鸭,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 寫在前面的話 代碼中的# > 表示的是輸出結(jié)果 輸入 使用input()函數(shù) 用法 注意input函數(shù)輸出的均是字...
    FlyingLittlePG閱讀 2,755評論 0 8
  • 什么是繼承 新類不必從頭編寫 新類從現(xiàn)有的類繼承,就自動擁有了現(xiàn)有類的所有功能 新類只需要編寫現(xiàn)有類缺少的新功能 ...
    Dozing閱讀 820評論 0 0
  • 一.繼承介紹 1 什么是繼承 繼承一種新建類的方式,新建的類稱之為子類/派生類,被繼承的類稱之為父類\基類\超...
    aq_wzj閱讀 315評論 0 0
  • property、魔法屬性和魔法方法欧芽、多重繼承和多繼承 1.5 property 學習目標 1. 能夠說出什么要...
    Cestine閱讀 794評論 0 1
  • 一. 子類繼承父類的構(gòu)造函數(shù) 現(xiàn)金盤平臺盤口搭建q<277.03.4.83.6> 子類不重寫 init莉掂,實例化子類...
    789ac4bce924閱讀 420評論 0 0