python語法學習之super(),繼承與派生_第1頁
python語法學習之super(),繼承與派生_第2頁
python語法學習之super(),繼承與派生_第3頁
python語法學習之super(),繼承與派生_第4頁
python語法學習之super(),繼承與派生_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

第python語法學習之super(),繼承與派生目錄1什么是繼承?2繼承的規(guī)則3繼承原理4多繼承屬性查詢順序5查找流程屬性查找6繼承概念的實現(xiàn)7私有屬性私有方法在繼承中的表現(xiàn)8派生類9屬性的覆蓋(派生屬性)10父類屬性(方法)的重用11繼承派生機制的作用12Super()

1什么是繼承?

繼承是一種創(chuàng)建新類的方式;

在Python中,新建的類可以繼承一個或多個父類,新建的類可稱為子類或派生類,父類又可稱為基類或超類。

繼承可以用來解決類與類之間的代碼重用性問題;

classParentClass1:#定義父類

pass

classParentClass2:#定義父類

pass

classSubClass1(ParentClass1):#單繼承

pass

classSubClass2(ParentClass1,ParentClass2):#多繼承

pass

注意:

在python中一個子類可以繼承多個父類,在其他語言中,一個子類只能繼承一個父類;

python中的繼承分為單繼承和多繼承;

通過類的內(nèi)置屬性__bases__可以查看類繼承的所有父類

SubClass2.__bases__

(class'__main__.ParentClass1',class'__main__.ParentClass2')

在Python3中只有新式類,即使沒有顯式地繼承object,也會默認繼承該類。

2繼承的規(guī)則

子類繼承父類的成員變量和成員方法:

子類不繼承父類的構(gòu)造方法,能夠繼承父類的析構(gòu)方法子類不能刪除父類的成員,但可以重定義父類成員子類可以增加自己的成員

示例:

#python中子類繼承父類成員變量之間的取值邏輯

classPerson():

def__init__(self,name,age,sex):

="jasn"

self.age='18'

self.sex=sex

deftalk(self):

print("iwanttospeaksomethingtoyo!!")

classChinese(Person):

def__init__(self,name,age,sex,language):

Person.__init__(self,name,age,sex)#用父類的name,age,sex覆蓋掉子類的屬性

self.age=age#覆蓋掉了父類的age,取值為子類實例中傳入age參數(shù)

self.language="chinese"

deftalk(self):

print("我說的是普通話?。?)

Person.talk(self)

obj=Chinese("nancy",'18','male',"普通話")

print()#對應場景A

print(obj.age)#對應場景B

print(obj.language)#對應場景C

obj.talk()#對應場景D

#總結(jié):

#A:若父類中初始化了成員變量,子類調(diào)用父類構(gòu)造方法未覆蓋屬性(),則調(diào)用子類屬性時取值為父類中初始化的成員變量;

#B:若父類中初始化了成員變量,若子類調(diào)用父類構(gòu)造方法覆蓋屬性(self.age)則取值為子類實例中傳入?yún)?shù)

#C:若父類未初始化該成員變量,則無論子類中有無進行對父類構(gòu)造方法進行屬性的覆蓋,均取子類實例中傳入的參數(shù)

#D:對于方法,如果子類有這個方法則直接調(diào)用,如果子類沒有則去父類查找。父類沒有則報錯

3繼承原理

對于你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表。

D.mro()#新式類內(nèi)置了mro方法可以查看線性列表的內(nèi)容,經(jīng)典類沒有該內(nèi)置方法

[class'__main__.D',class'__main__.B',class'__main__.C',class'__main__.A',class'object']

python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止,而這個MRO列表的構(gòu)造是通過一個C3線性化算法來實現(xiàn)的。

實際上就是合并所有父類的MRO列表并遵循如下三條準則:

子類會先于父類被檢查多個父類會根據(jù)它們在列表中的順序被檢查如果對下一個類存在兩個合法的選擇,選擇第一個父

Python中的MRO方法搜索順序

Python中針對類提供了一個內(nèi)置屬性mro可以查看方法搜索順序

MRO是methodresolutionorder,主要用于在多繼承時判斷方法、屬性的調(diào)用路徑。

print(C.__mro__)#C是多繼承后的類名

輸出結(jié)果:

(class__main__.C,class__main__.A,class__main__.B,classobject)

在搜索方法時,是按照mro的輸出結(jié)果從左至右的順序查找的;

如果在當前類中找到方法,就直接執(zhí)行,不再搜索;如果沒有找到,就查找下一個類中是否有對應的方法,如果找到,就直接執(zhí)行,不再搜索。

如果找到最后一個類,還沒有找到方法,程序報錯。

4多繼承屬性查詢順序

(1)多繼承結(jié)構(gòu)為菱形結(jié)構(gòu)

如果繼承關(guān)系為菱形結(jié)構(gòu),那么經(jīng)典類與新式類會有不同MRO。

箭頭表示搜索順序

(2)多繼承結(jié)構(gòu)為非菱形結(jié)構(gòu)

會按照先找B這一條分支,然后再找C這一條分支,最后找D這一條分支的順序直到找到我們想要的屬性。

5查找流程

①由對象發(fā)起的屬性查找,會從對象自身的屬性里檢索,沒有則會按照對象的類.mro()規(guī)定的順序依次找下去。

②由類發(fā)起的屬性查找,會按照當前類.mro()規(guī)定的順序依次找下去。

主要知識點:類的__mro__屬性的用法;

屬性查找

有了繼承關(guān)系,對象在查找屬性時,先從對象自己的__dict__中找,如果沒有則去子類中找,然后再去父類中找.....

classFoo:

deff1(self):

print('Foo.f1')

deff2(self):

print('Foo.f2')

self.f1()

classBar(Foo):

deff1(self):

print('Bar.f1')

b=Bar()

b.f2()

#運行結(jié)果:

Foo.f2

Bar.f1

#運行流程分析:

b.f2()會在父類Foo中找到f2,先打印Foo.f2,然后執(zhí)行到self.f1(),即b.f1(),仍會按照:對象本身-類Bar-父類Foo的順序依次找下去,在類Bar中找到f1,因而打印結(jié)果為Bar.f1

父類如果不想讓子類覆蓋自己的方法,可以采用雙下劃線開頭的方式將方法設置為私有的:

classFoo:

def__f1(self):#變形為_Foo__f1

print('Foo.f1')

deff2(self):

print('Foo.f2')

self.__f1()#變形為self._Foo__f1,然后回到Bar類中找,沒有,再到Foo中找到了

classBar(Foo):

def__f1(self):#變形為_Bar__f1

print('Bar.f1')

b=Bar()#Bar類處于執(zhí)行階段,_Bar__f1變?yōu)開_f1

b.f2()#在父類中找到f2方法,進而調(diào)用b._Foo__f1()方法,是在父類中找到的f1方法

#運行結(jié)果:

Foo.f2

Foo.f1

6繼承概念的實現(xiàn)

方式主要有2類:

實現(xiàn)繼承接口繼承

①實現(xiàn)繼承是指使用基類的屬性和方法而無需額外編碼的能力。

②接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現(xiàn)的能力(子類重構(gòu)爹類方法)。

在考慮使用繼承時,有一點需要注意,那就是兩個類之間的關(guān)系應該是屬于關(guān)系。

例如:Employee是一個人,Manager也是一個人,因此這兩個類都可以繼承Person類,但是Leg類卻不能繼承Person類,因為腿并不是一個人。

7私有屬性私有方法在繼承中的表現(xiàn)

父類中的私有方法和私有屬性都是不能被子類繼承下來的;

測試示例:父類中的私有屬性和私有方法是否能被繼承下來?

classPerpon:

num=20

__num1=12

def__test1(self):

print('__test1....')

deftest2(self):

print('test2...')

classStudent(Perpon):

deftest(self):

print('num...')

print(self.num)

#print(Student.__num1)

self.test2()

#self.__test1()

student=Student()

student.test()

student.test2()

#student.__test1()#報錯

num...

test2...

test2...

'''

8派生類

1)在父類的基礎上產(chǎn)生子類,產(chǎn)生的子類就叫做派生類

2)父類里沒有的方法,在子類中有了,這樣的方法就叫做派生方法。

3)父類里有,子類也有的方法,就叫做方法的重寫(就是把父類里的方法重寫了)

classHero:

def__init__(self,nickname,aggressivity,life_value):

self.nickname=nickname

self.aggressivity=aggressivity

self.life_value=life_value

defattack(self,enemy):

print('Heroattack')

classGaren(Hero):

camp='Demacia'

defattack(self,enemy):#self=g1,enemy=r1

#self.attack(enemy)#g1.attack(r1),這里相當于無限遞歸

Hero.attack(self,enemy)#引用父類的attack,對象會去跑父類的attack

print('fromgarenattack')#再回來這里

deffire(self):

print('%sisfiring'%self.nickname)

classRiven(Hero):

camp='Noxus'

g1=Garen('garen',18,200)

r1=Riven('rivren',18,200)

g1.attack(r1)

#print(g1.camp)

#print(r1.camp)

#g1.fire()

9屬性的覆蓋(派生屬性)

子類也可以添加自己新的屬性或者在自己這里重新定義這些屬性(不會影響到父類);

需要注意的是:一旦重新定義了自己的屬性且與父類重名,那么調(diào)用新增的屬性時,就以自己為準了(屬性的覆蓋)。

示例:

#派生屬性:子類中自己添加的新屬性

#屬性的覆蓋:子類和父類有相同屬性,調(diào)用自己的

classPerpon:

num=20

def__init__(self,name):

print('person...')

classStudent(Perpon):

num=10#把父類中的20覆蓋

def__init__(self,name,age):#age為派生屬性

super().__init__(name)

=name

self.age=age

print('student...')

defstudy(self):

print(super().num)

pass

student=Student('趙四',23)

print()#person...

print(student.age)

print(student.num)

student.study()

person...

student...

'''

10父類屬性(方法)的重用

指名道姓的重用

classA:

def__init__(self):

print('A的構(gòu)造方法')

classB(A):

def__init__(self):

print('B的構(gòu)造方法')

A.__init__(self)

classC(A):

def__init__(self):

print('C的構(gòu)造方法')

A.__init__(self)

classD(B,C):

def__init__(self):

print('D的構(gòu)造方法')

B.__init__(self)#先找到B,B調(diào)用A,等這個線性任務處理完之后,在繼續(xù)下一行代碼

C.__init__(self)#先找到C,C里面也調(diào)用A的方法

pass

f1=D()#A.__init__被重復調(diào)用

D的構(gòu)造方法

B的構(gòu)造方法

A的構(gòu)造方法

C的構(gòu)造方法

A的構(gòu)造方法

'''

Super()方法重用

classA:

def__init__(self):

print('A的構(gòu)造方法')

classB(A):

def__init__(self):

print('B的構(gòu)造方法')

super(B,self).__init__()

classC(A):

def__init__(self):

print('C的構(gòu)造方法')

super(C,self).__init__()

classD(B,C):

def__init__(self):

print('D的構(gòu)造方法')

super().__init__()#super(D,self).__init__()

f1=D()#super()會基于mro列表,往后找

D的構(gòu)造方法

B的構(gòu)造方法

C的構(gòu)造方法

A的構(gòu)造方法

#super()語法

#super(type[,object-or-type])type當前類,object-or-type為實例化對象,一般默認為self,不過該參數(shù)在python3中默認

super()是一個特殊的類,調(diào)用super得到一個對象,該對象指向父類的名稱空間。

派生與繼承解決問題:子類重用父類的屬性,并派生出新的屬性。

注意:使用哪一種都可以,但不能兩種方式混合使用!

11繼承派生機制的作用

可以將一些共用的功能加在基類中,實現(xiàn)代碼的共享;

在不改變基類的基礎上改變原有的功能;

練習:

list類里只有append向末尾加一個元素的方法,但沒有向列表頭部添加元素的方法,試想能否為列表在不改變原有功能的基礎上添加一個inster_head(x)方法,此方法能在列表的前部添加元素?

classMylist(list):

definsert_head(self,x):

#self.reverse()

#self.append(x)

#self.reverse()

self.insert(0,x)#直接在最開始插入x

myl=Mylist(range(3,6))

print(myl)#[3.4.5]

myl.insert_head(2)

print(myl)#[2,3,4,5]

myl.append(6)

print(myl)#[2,3,4,5,6]

12Super()

super(cls,obj)返回被綁定超類的實例(要求obj必須為cls類型的實例)

super()返回被綁定超類的實例,等同于:super(class,實例方法的第一個參數(shù),必須在方法內(nèi)調(diào)用)

格式:

父類類名.方法名稱(self)或者super().方法名稱()或者super(本類類名,對象名)

作用:借助super()返回的實例間接調(diào)用父類的覆蓋方法;

示例:

#此示例示意用super函數(shù)間接調(diào)用父類的

classA:

defwork(self):

print('A.work被調(diào)用')

classB(A):

'''B類繼承子A類'''

defwork(self):

print('B.work被調(diào)用')

defsuper_work(self):

#調(diào)用b類自己的work方法

self.work()

#調(diào)用父類的work

super(B,self).work()

super().work()#此種調(diào)用方式只能在實例方法內(nèi)調(diào)用

b=B()

#b.work()#B.work被調(diào)用!!

#super(B,b).work()#A.work被調(diào)用

b.super_work()

#super_work()#出錯

調(diào)用super()會得到一個特殊的對象,該對象專門用來引用父類的屬性,且繼承順序嚴格遵循mro繼承序列;

示例:

classFather1:

x=10

pass

classFather2:

x=20

pass

#多繼承的情況下,從左到右

classSub(Father1,Father2):

def__init__(self):#注意__int__不是__init__

print(super().__delattr__)

print(Sub.mro())#[class'__main__.Sub',class'__main__.Father1',class'__main__.Father2',class'object']

obj=Sub()

print(object)#class'object'

mro():會把當前類的繼承關(guān)系列出來,嚴格按照mro列表的順序往后查找

classA:#默認繼承object

deftest(self):

print('fromA.test')

super().test()

classB:

deftest(self):

print('fromB.test')

classC(A,B):

pass

c=C()

#檢查super的繼承順序

#mro():會把當前類的繼承關(guān)系列出來。

print(C.mro())#[class'__main__.C',class'__main__.A',class'__main__.B',class'object']

c.test()#fromA.test

#fromB.test

使用super調(diào)用父類中的方法,注意分析程序的執(zhí)行順序。

classParent(object):

def__init__(self,name,*args,**kwargs):#為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)

print('parent的init開始被調(diào)用')

=name

print('parent的init結(jié)束被調(diào)用')

classSon1(Parent):

def__init__(self,name,age,*args,**kwargs):#為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)

print('Son1的init開始被調(diào)用')

self.age=age

super().__init__(name,*args,**kwargs)#為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)

print('Son1的init結(jié)束被調(diào)用')

classSon2(Parent):

def__init__(self,name,gender,*args,**kwargs):#為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)

print('Son2的init開始被調(diào)用')

self.gender=gender

super().__init__(name,*args,**kwargs)#為避免多繼承報錯,使用不定長參數(shù),接受參數(shù)

print('Son2的init結(jié)束被調(diào)用')

classGrandson(Son1,Son2):

def__init__(self,name,age,gender):

print('Grandson的init開始被調(diào)用')

#多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍

#而super只用一句話,執(zhí)行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因

#super(Grandson,self).__init__(name,age,gender)效果和下面的一樣

super().__init__(name,age,gender)

print('Grandson的init結(jié)束被調(diào)用')

print(Grandson.__mro__)#搜索順序

gs=Grandson('grandson',12,'男')

print('姓名:',)

print('年齡:',gs.age)

print('性別:',gs.gender)

'''結(jié)果如下:

(class'__main__.Grandson',class'__main__.Son1',class'__main__.Son2',class'__main__.Parent',class'object')

Grandson的init開始被調(diào)用

Son1的init開始被調(diào)用

Son2的init開始被調(diào)用

parent的init開始被調(diào)用

parent的init結(jié)束被調(diào)用

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論