Day 5-2 類的繼承和派生,重用
類的繼承
派生
在子類中重用父類
組合
定義:
繼承指的是類與類之間的關系,是一種什麽“是”什麽的關系,繼承的功能之一就是用來解決代碼重用問題.
繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可以成為基類或超類,新建的類稱為派生類或子類.
1 # 我們定義的2個英雄都有一些相似的特征和技能.都屬於英雄類,那麽我們就可以定義個英雄類,然後讓英雄繼承英雄類的特征和技能 2 3 class Hero: 4 def __init__(self, name, life_value, aggressivity): 5 self.name = name繼承類和查看父類6 self.life_value = life_value 7 self.aggressivity = aggressivity 8 9 def attck(self,enemy): 10 enemy.life_value -= self.aggressivity 11 12 13 class Garen(Hero): 14 pass 15 16 17 class Riven(Hero): 18 pass 19 20 21 print(Garen.__bases__) # 查看Graren的父類. 22g1 = Garen("草叢倫", 100, 50) 23 r1 = Riven("兔女郎", 80, 60) 24 print(r1.life_value) 25 # A, 我們通過Garen這個類,來產生一個對象g1.但是Garen這個類中,我們並未定義__init__方法.但是我們也定義成功了,並沒有報錯.為什麽呢? 26 # B, 因為Garen這個類繼承了Hero這個父類中的數據屬性和函數屬性.
提示:如果沒有指定基類,python的類會默認繼承object類,object是所有python類的基類,它提供了一些常見方法(如__str__)的實現。
派生
當然子類也可以添加自己新的屬性或者在自己這裏重新定義這些屬性(不會影響到父類),需要註意的是,一旦重新定義了自己的屬性且與父類重名,那麽調用新增的屬性時,就以自己為準了。簡單的來說,派生就是子類自己定義自己獨有的特征或方法.
繼承的實現原理
python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表.
>>> F.mro() #等同於F.__mro__ [<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>]
所有父類的MRO列表並遵循如下三條準則:
- 子類會先於父類被檢查
- 多個父類會根據它們在列表中的順序被檢查
- 如果對下一個類存在兩個合法的選擇,選擇第一個父類
繼承的查找:
1 #驗證多繼承情況下的屬性查找 2 3 class A: 4 # def test(self): 5 # print(‘from A‘) 6 pass 7 8 class B(A): 9 # def test(self): 10 # print(‘from B‘) 11 pass 12 13 class C(A): 14 # def test(self): 15 # print(‘from C‘) 16 pass 17 18 class D(B): 19 # def test(self): 20 # print(‘from D‘) 21 pass 22 23 class E(C): 24 # def test(self): 25 # print(‘from E‘) 26 pass 27 28 class F(D,E): 29 # def test(self): 30 # print(‘from F‘) 31 pass 32 33 34 #F,D,B,E,C,A 35 36 print(F.mro()) 37 # f=F() 38 # f.test()查找方式
在PY3中,都是新式類,沒有經典類了.
經典類:在py2中.定義一個類.class Her0().如果括號裏,沒有繼承基類object.它就是一個經典類.如果class Hero(object),那麽就是一個新式類
py3中.如果一個類沒有繼承,那麽默認繼承object.
子類中重用父類
方式1,指名道姓的方式.(不依賴與繼承)
1 class Hero: 2 def __init__(self, name, life_value, aggressivity): 3 self.name = name 4 self.life_value = life_value 5 self.aggressivity = aggressivity 6 7 def attck(self,enemy): 8 enemy.life_value -= self.aggressivity 9 10 11 class Garen(Hero): 12 13 def __init__(self, name, life_value, aggressivity, weapon): 14 Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的調用父類中的方法. 15 self.weapon = weapon 16 17 def attck(self,enemy): 18 Hero.attck(self,enemy) # 指名道姓的調用父類中的方法. 19 print("in Garen class") 20 21 22 class Riven(Hero): 23 pass 24 25 26 27 g1 = Garen("草叢倫", 100, 50,"黑切") 28 29 print(g1.__dict__) # 查看g1的dict中,已經有了黑切.指名道姓法
方式2,super() (依賴於繼承)
1 # 方式2, super() 依賴繼承 2 class Hero: 3 def __init__(self, name, life_value, aggressivity): 4 self.name = name 5 self.life_value = life_value 6 self.aggressivity = aggressivity 7 8 def attck(self,enemy): 9 enemy.life_value -= self.aggressivity 10 11 12 class Garen(Hero): 13 14 def __init__(self, name, life_value, aggressivity, weapon): 15 # Hero.__init__(self,name, life_value, aggressivity) # 指名道姓的調用父類中的方法. 16 # super(Garen,self).__init__(name,life_value,aggressivity) 17 super().__init__(name,life_value,aggressivity) # 簡寫 18 self.weapon = weapon 19 20 def attck(self,enemy): 21 # Hero.attck(self,enemy) # 指名道姓的調用父類中的方法. 22 # super(Garen,self).attck(enemy) # super方法,括號裏的Garen的位置是子類的名稱,self是生成對象的名稱.後面是調用的方法. 23 super().attck(enemy) # 在py3中,可以簡寫成這樣. 24 print("in Garen class") 25 26 27 28 class Riven(Hero): 29 pass 30 31 32 33 g1 = Garen("草叢倫", 100, 50,"黑切") 34 r1 = Riven("兔女郎瑞文", 80,50) 35 g1.attck(r1) 36 print(r1.life_value) 37 38 print(g1.__dict__) # 查看g1的dict中,已經有了黑切.super方法
1 class A: 2 def f1(self): 3 print("from A") 4 super().f1() #在這裏調用super().f1()的時候.基於的是C這個類的mro列表進行查找的.並不是說,在A類中調用super,就是在A類中,查找A的父類中的f1方法 5 6 class B: 7 def f1(self): 8 print("from B") 9 10 class C(A,B): 11 pass 12 13 print(C.mro()) 14 i = C() 15 i.f1() # 查找f1的是,都是基於對象i來進行查找的.如果i裏沒有f1方法.那麽就去它的類中查找,如果類中沒有,就去類所繼承的父類中按照mro列表查找.super繼承驗證
組合
軟件重用的重要方式除了繼承之外還有另外一種方式,即:組合
組合指的是,在一個類中以另外一個類的對象作為數據屬性,稱為類的組合.
組合與繼承都是有效地利用已有類的資源的重要方式。但是二者的概念和使用場景皆不同,
1.繼承的方式
通過繼承建立了派生類與基類之間的關系,它是一種‘是‘的關系,比如白馬是馬,人是動物。
當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老師是人,學生是人
2.組合的方式
用組合的方式建立了類與組合的類之間的關系,它是一種‘有’的關系,比如教授有生日,教授教python和linux課程,教授有學生s1、s2、s3...
1 class People: 2 """定義人類""" 3 school = "luffycity" 4 def __init__(self, name, age, sex): 5 self.name = name 6 self.age = age 7 self.sex =sex 8 9 class Teacher(People): 10 """定義一個人教師類""" 11 def __init__(self, name, age, sex, level, salary): 12 super().__init__(name, age, sex) 13 self.level = level 14 self.salary = salary 15 16 def teach(self): 17 print("%s is teaching" % self.name) 18 19 20 class Students(People): 21 """定義一個學生類""" 22 def __init__(self, name, age, sex, grade): 23 super().__init__(name, age, sex) 24 self.grade = grade 25 26 def learn(self): 27 print("%s is learning" % self.name) 28 29 30 class Course: 31 """定義一個課程類""" 32 def __init__(self, course_name, course_price, course_period): 33 self.course_name = course_name 34 self.course_price = course_price 35 self.course_period = course_period 36 37 def tell_info(self): 38 print("課程名:%s, 課程價格:%s, 課程周期:%s" % (self.course_name, self.course_price, self.course_period)) 39 40 41 42 class Bron_date: 43 """定義一個生日類""" 44 def __init__(self, year, mon, day): 45 self.year = year 46 self.mon = mon 47 self.day = day 48 def tell_info(self): 49 print("生日:%s年%s月%s日" % (self.year, self.mon, self.day)) 50 51 # t1 = Teacher("alex", 22, "男", "一級", 100000) 52 #生成一個stu1的學生對象 53 stu1 = Students("傑克", 18, "男", "python全棧開發") 54 #生成一個python的課程對象 55 python = Course("python", 8999, "6mons") 56 # 把python對象賦給stu1.course.學生stu1有課程.這裏就是組合 57 stu1.course = python 58 #輸入sut1的課程信息組合實例
Day 5-2 類的繼承和派生,重用