繼承
1:什么是繼承
繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,也就是說在python中支持一個兒子繼承多個爹。
新建的類成為子類或者派生類。
父類又可以成為基類或者超類。
子類會遺傳父類的屬性。
2:為什么要用繼承
減少代碼冗余(也就是重復寫代碼)。
3:怎么用繼承:
我們定義兩個類; class parenclass1: pass class parenclass2: pass 在定義兩個類: class subclass1: pass class subclass2: pass 我想讓 : class parenclass1: 作為 class subclass1: 的父類。 pass pass
應該這樣用: class subclass1( parenclass1): 這就表示subclass1是子類,parenclass 是subclass1 的父類 pass
兩個父類的話怎么表達呢?如下: class subclass2(parenclass1,parenclass2): pass 這就表示subclass2的父類是parenclass1,parenclass2 這兩個
想要查看子類的父類 應該怎樣查看呢: 用__bases__ 如下:
class ParentClass1: pass class ParentClass2: pass class Subclass1(ParentClass1): pass class Subclass2(ParentClass1,ParentClass2): pass print(Subclass1.__bases__) #打印結果:(<class '__main__.ParentClass1'>,) print(Subclass2.__bases__) #打印結果: (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
經典類與新式類
1、只有在python2中才分新式類和經典類,python3中統一都是新式類 2、在python2中 沒有顯示繼承的object類的類,以及該類的子類都是經典類 3、在python2中,顯示的聲明繼承object的類,以及該類的子類都是新式類 4、在python3中,無論是否繼承object,都默認 繼承object,即python3中所有類均為新式類 至於經典類 與新式類的區別,后面會有討論。 提示:如果沒有指定基類, python的類會默認繼承object類, object是所有python類的基類。
二、繼承與抽象
繼承描述的是子類與父類之間的關系,是一種什么的關系呢? 要找出這種關系, 必須先抽象在繼承。
抽象即抽取類似或者說比較像的部分。
抽象分成兩個層次:
1.將奧巴馬和梅西這倆對象比較像的部分抽取成類;
2.將人,豬,狗這三個類比較像的部分抽取成父類。
抽象最主要的作用是划分類別(可以隔離關注點,降低復雜度)
繼承:是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象合格過程, 才能通過繼承的方式去表達抽象的結構。
抽象只是分析和設計的過程,一個動作或者說一種技巧,通過抽象可以得到類
例如:我們寫一個老男孩的老師與學生的類,若是不涉及到繼承的話 我們正常是這樣寫
class OldboyTeacher: school = 'oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def change_score(self): print('teacher %s is changing score ' %self.name) class Oldboystudent:
school = 'oldboy’
def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def choose(self): print('student %s choose course' %self.name) tea1 = OldboyTeacher('egon', 18, 'male') #OldboyTeacher.__init__(...) stu1=Oldboystudent('alex',73,'female') print(tea1.name,tea1.age,tea1.sex) # egon 18 male
print(stu1.name) #alex
但是我們經過分析 發現里面里面有許多重復代碼, 這時我們可以用到類的繼承來寫了。如下:
class OldboyPeople: school ='oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Oldboyteacher(OldboyPeople): def change_score(self): print('teacher %s is changing score ' %self.name)
class Oldboystudent(OldboyPeople): def choose(self): print('student %s choose course'%self.name) tea1 = Oldboyteacher('egon', 18, 'male') stu1=Oldboystudent('alex',73,'female')
print(tea1.name,tea1.age,tea1.sex)#egon 18 male print(stu1.name) #alex
三、基於繼承在看屬性查找
我們先看一個列子
class Foo: def f1(self): print('Foo.f1') def f2(self): #self=obj print('Foo.f2') #在父類中找到發 f2屬性,第3步打印這一行 self.f1() #obj.f1() 第4步再去掉用self的f1屬性 class Bar(Foo): def f1(self):#第五步, 在回到object自身的名稱空間找f1屬性,找到后調用 print('Bar.f1') #第6步 執行 obj=Bar() #第一步 :類的實例化, 先得到一個空對象, obj.f2() #第2步:空對象調用f2屬性 在自身尋找f2屬性, 沒有找到就去父類中尋找
#結果
Foo.f2
Bar.f1
注意子類的屬性查找,一定是優先查找子類自己本身的屬性與特征, 在本身沒有的情況下 在去父類中查找。
四、派生
派生:子類定義自己新的屬性,如果與父類同名,以子類自己的為准。
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def f1(self): print('爹的f1') class OldboyTeacher(OldboyPeople): def change_score(self): print('teacher %s is changing score' %self.name) def f1(self): print('兒子的f1') tea1 = OldboyTeacher('egon', 18, 'male') tea1.f1()
#調用顯示:兒子的f1
# 父類和子類中都有f1, 優先調用自己的屬性,所以結果調用的是兒子的f1
五、在子類中派生出的新方法重用父類的功能
拿上一案例來舉例 在oldboyteacher 這個類中要添加薪水與級別。 然后調用。 有兩種方式。
方式一:指名道姓的調用(與繼承沒有什么關系)
class OldboyPeople: school ='oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def tell_info(self): print( ''' ====個人信息==== 姓名:%s 年齡:%s 性別:%s '''%(self.name,self.age,self.sex)) class OldboyTeacher(OldboyPeople): def __init__(self,name,age,sex,level,salary): OldboyPeople.__init__(self,name,age,sex) #在這里指明道姓來調用這一個函數里的屬性 self.level =level self.salary=salary def tell_info(self): OldboyPeople.tell_info(self) #指名道姓的來調用這個函數里的屬性 print(""" 等級:%s 薪資:%s """ %(self.level,self.salary)) tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1) print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary) tea1.tell_info() #打印結果: egon 18 male 9 3.1 ====個人信息==== 姓名:egon 年齡:18 性別:male 等級:9 薪資:3.1
方法二、
用super()調用(嚴格依賴於繼承)
super() 的返回值是一個特殊的對象,該對象專門用來調用父類中的屬性, 一般在python2中,需要super(自己的類名,self), 而python3中,括號里面一般不填類名
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(""" ===========個人信息========== 姓名:%s 年齡:%s 性別:%s """ %(self.name,self.age,self.sex)) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary): super().__init__(name,age,sex) self.level = level self.salary = salary def tell_info(self): super().tell_info() print(""" 等級:%s 薪資:%s """ %(self.level,self.salary)) tea1 = OldboyTeacher('egon', 18, 'male', 9, 3.1) print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary) tea1.tell_info() #調用結果: egon 18 male 9 3.1 ===========個人信息========== 姓名:egon 年齡:18 性別:male 等級:9 薪資:3.1
六:經典類 與新式類
1新式類:
繼承object的類,以及該類的子類,都是新式類
在python3中,如果一個類沒有指定繼承的父類,默認就繼承object
所以說在python3中所有的類都是新式類
2經典類:(只有在python2才區分經典類和新式類):
沒有繼承object的類,以及該類的子類 都是經典類
1 經典類:深度優先
2 新式類:廣度優先
如果繼承關系為非菱形結果嗎則會按照先找B 這一條分支,然后在找c這一條分支,最后找D這一條分支的順序,直到找到我們想要的屬性
當繼承關系為菱形結構時
經典類查找順序:
若是在A 類里自己沒找到, 則會先去B類里去找, B類里沒找到,就會在E類里找, 然后在G類里找,
G類里沒找到 會去C 類里找, 然后去F 類里找,最后去D 類里找。
新式類查找順序:
按照圖中1 ,2 , 3, 4,5,6的順序查找, 這個為廣度優先的查找方式
七: super()依賴繼承
super()會嚴格按照mro列表從當前查找到的位置繼續往后查找
class A: def test(self): print('A.test') #2 執行這一步 打印 super().f1 #3 然后在調用父類里的f1, 根據C.mro里的查找順序執行到A 往后繼續執行到B里去查找 class B: def f1(self): #4找到f1, 執行 print('from B') #5打印 class C(A,B): pass c=C() print(C.mro()) #調用屬性的順序 [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>] c.test() #1:C里沒有 ,去A里調用
#打印結果
A.test
from B