python面向對象—03-繼承、多繼承、super
階段一:繼承
情景模式:假設你正在參與一個魔幻類角色遊戲的開發,公司需要你為這個遊戲設計兩個角色的類:
- 劍士
- 具有如下屬性:
- 角色名
- 角色等級
- 生命值
- 攻擊力
- 具有如下行為:
- 實體攻擊
- 具有如下屬性:
- 法師
- 具有如下屬性:
- 角色名
- 角色等級
- 生命值
- 攻擊力
- 具有如下行為:
- 實體攻擊
- 具有如下屬性:
代碼實作:
英勇的劍士:
class SwordsMan:
def __init__(self, name, level, blood, attack_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
self.name = name
self.level = level
self.blood = blood
self.power = attack_power
def fight(self): #角色攻擊行為
print('實體攻擊')
def __str__(self):
return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
name = self.name,
level = self.level,
blood = self.blood)
智慧的法師:
class Magician:
def __init__(self, name, level, blood, magic_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
self.name = name
self.level = level
self.blood = blood
self.power = magic_power
def fight(self): #角色攻擊行為
print('魔法攻擊')
def __str__(self):
return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
name = self.name,
level = self.level,
blood = self.blood)
繼承 問題引入
問題一: 兩個中有大量重複的代碼,是否能夠隻寫一次 ?
- 抽象出一個更抽象的類,放公共代碼
問題二: 繼承的意義是什麼 ?
- 重用代碼,友善代碼的管理和修改
問題三: 繼承是複制變量空間嘛 ?
- 繼承不是變量空間複制
分類關系圖
對以上連個角色進行進一步抽象,定義一個更加抽象的類— 角色類
代碼如下:
class Rloe:
def __init__(self,name,level,blood):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
self.name = name
self.level =level
self.blood = blood
def __str__(self):
return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
name = self.name,
level = self.level,
blood = self.blood)
def fight(self): # 角色攻擊行為
raise NotImplementedError('必須在子類中實作該行為')
繼承關系圖
再從角色類中派生具體的類
注意:(派生與繼承是一個意思的兩個說法)
派生出的劍士:
class SwordsMan(Rloe): #繼承自Role
def __init__(self,name,level,blood,attack_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
Rloe.__init__(self,name,level,blood)
self.attack_power = attack_power
def fight(self): #角色攻擊行為
print('實體攻擊')
派生出的法師:
class Magician: #繼承自Role
def __init__(self,name,level,blood,magic_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
Rloe.__init__(self, name, level, blood)
self.attack_power = attack_power
def fight(self): #角色攻擊行為
print('魔法攻擊')
def cure(self): # 角色技能
print('治療')
繼承搜尋
搜尋原則:(通路類的屬性或方法)
- 如果找不到轉到其父類中查找
- 如果再找不到轉到其父類的父類中查找
執行個體:
class BaseClass:
attritube =
def method(self):
pass
class DeriverClass: #簡單繼承,沒有任何的封裝,重寫
pass
print(DeriverClass.__dict__) #DeriverClass中沒有attritube與method
print(BaseClass.__dict__) #BaseClass中有
重用父類的 _ init_
左邊的self 是 劍士(子類)的執行個體 右邊的self是也是劍士的執行個體
頂級基類 object
class ClassName:
pass
class ClassN(object):
pass
print(ClassName.__bases__)
print(ClassN.__bases__)
思考:為什麼傳回的是一個元祖 ?
- 有可能繼承多個類(及多繼承),以元組顯示。
階段二:多重繼承
多重繼承 問題引入
問題一: 一個類隻能有一個基類嘛 ?
問題二: 如果有多個基類,如果有同名屬性和方法,應該如何選擇?
問題三: 有沒有一種更加優雅的方式調用父類的方法 ?
繼承關系圖:
代碼實作如下:
class D:
pass
class E:
pass
class C:
pass
class B(D,E):
pass
class A(B,C):
pass
print(A.mro())
結果輸出:
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.C'>, <class 'object'>]
程序已結束,退出代碼0
MRO-C3 搜尋分析
S[D] = <D O>
S[E] = <E O>
S[C] = <C O>
S[B] = B + merge(S[D], S[E], <D E>)
= B + merge(<D O>, <E O>, <D E>)
= <B D> + merge(O, <E O>, E)
= <B D E O>
S[A] = A + merge(S[B], S[C], <B C>)
= A + merge(<B D E O>, <C O>, <B C>)
= <A B> + merge(<D E O>, <C O>, C)
= <A B D> + merge(<E O>, <C O>, C)
= <A B D E> + merge(O, <C O>, C)
= <A B D E C O>
由于沖突導緻的不能繼承
代碼實作如下:
class A:
pass
class B:
pass
class C(A,B):
pass
class D(B,A):
pass
class E(C,D):
pass
print(E.mro())
結果輸出:
Traceback (most recent call last):
File "G:/xxx/xxx/xxx/xxx/TTT.py", line , in <module>
class E(C,D):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B
MRO-C3 搜尋分析
S[A] = <A O>
S[B] = <B O>
S[C] = C + merge(S[A], S[B], <A B>)
= C + merge(<A O>, <B O>, <A B>)
= <C A> + merge(O, <B O>, <B>)
= <C A B O>
S[D] = <D B A O>
S[E] = E + merge(S[C], S[D], <C D>)
= E + merge(<C A B O>, <D B A O>, <CD>)
= <E C> + merge(<A B O>, <D B A O>, <D>)
= <E C D> + merge(<A B O>, <B A O>) # 沖突
鴨子類型
執行個體:
def draw_fight(role):
print('role',end='')
role.fight() #其實并不關心,role是不是一個執行個體
class SwordsMan:
def __init__(self, name, level, blood, attack_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
self.name = name
self.level = level
self.blood = blood
self.power = attack_power
def fight(self): #角色攻擊行為
print('實體攻擊')
def __str__(self):
return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
name = self.name,
level = self.level,
blood = self.blood)
class Magician:
def __init__(self, name, level, blood, magic_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
self.name = name
self.level = level
self.blood = blood
self.power = magic_power
def fight(self): #角色攻擊行為
print('魔法攻擊')
def __str__(self):
return "{clc}({name},{level},{blood})".format(clc = self.__class__.__name__,
name = self.name,
level = self.level,
blood = self.blood)
s = SwordsMan('lili',,,)
m = Magician('haha',,,)
draw_fight(s) #列印出:role實體攻擊
draw_fight(m) #列印出:role魔法攻擊
如果走起路來像鴨子,或者叫起來像鴨子,那就是鴨子!
基于多繼承的 Mix-in 設計模式
原則:
- 最好,多繼承就一層,且是最後一層
- 注意:一般,“Mix-in類”是繼承的終點 !
階段三:super 内置函數
如何更加優雅的調用父類中方法?
代碼實作如下:
劍士super方法改進:
class SwordsMan(Rloe): #繼承自Role
def __init__(self,name,level,blood,attack_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
super().__init__(name,level,blood)
self.attack_power = attack_power
def fight(self): #角色攻擊行為
print('實體攻擊')
法師劍士super方法改進:
class Magician: #繼承自Role
def __init__(self,name,level,blood,magic_power):
'''
:param name:角色姓名
:param level:角色等級
:param blood:角色血量
'''
super().__init__(name, level, blood)
self.attack_power = attack_power
def fight(self): #角色攻擊行為
print('魔法攻擊')
def cure(self): # 角色技能
print('治療')
super不需要再傳self、super是通過mro查找的
練習:
eg:
假設你正在參與潭州教育公司的軟體學員管理系統開發,需要你為系統設計學員類:潭州教育軟體類别:
- C/C++
- Web前端
- Python
請設計一個基類表示學員,然後使用繼承來實作各科目的軟體學員。
代碼實作如下:
class Student:
def __init__(self,name,age,sex):
'''
:param name:學員姓名
:param age:學員年齡
:param sex:學員性别
'''
self.name = name
self.age =age
self.sex = sex
def __str__(self):
return "{clc}({name},{age},{sex})".format(clc = self.__class__.__name__,
name = self.name,
age = self.age,
sex = self.sex)
def learn(self): # 學員學習課程
raise NotImplementedError('必須在子類中實作該方法')
class C(Student): #繼承自Student
def __init__(self,name,age,sex,lesson):
'''
:param name:學員姓名
:param age:學員年齡
:param sex:學員性别
'''
super().__init__(name,age,sex)
self.lesson = lesson
def learn(self): #學習課程
print('學習C/C++課程')
class Web(Student): #繼承自Student
def __init__(self,name,age,sex,lesson):
'''
:param name:學員姓名
:param age:學員年齡
:param sex:學員性别
'''
super().__init__(name,age,sex)
self.lesson = lesson
def learn(self): #學習課程
print('學習Web前端課程')
class Python(Student): #繼承自Student
def __init__(self,name,age,sex,lesson):
'''
:param name:學員姓名
:param age:學員年齡
:param sex:學員性别
'''
super().__init__(name,age,sex)
self.lesson = lesson
def learn(self): #學習課程
print('學習Python課程')
c= C('lili',,'M','c/c++')
w= Web('haha',,'F','Web前端')
p= Python('dada',,'M','Python')
print(c)
c.learn()
print(w)
w.learn()
print(p)
p.learn()
輸出結果:
C(lili,,M)
學習C/C++課程
Web(haha,,F)
學習Web前端課程
Python(dada,,M)
學習Python課程
>>>