1. 程式人生 > >python-繼承與重用

python-繼承與重用

name period fir 相同 attack img 隔離 基類 但是

什麽是繼承?

繼承是一種創建新類的方式,新建的類可以繼承一個或多個父類(python支持多繼承),父類又可稱為基類或超類,新建的類稱為派生類或子類。子類會“”遺傳”父類的屬性,從而解決代碼重用問題(比如練習7中Garen與Riven類有很多冗余的代碼)

單繼承與多繼承

class ParentClass_one: #定義父類
pass

class ParentClass_two: #定義父類
pass

class SubClass_one(ParentClass_one): #單繼承,基類是ParentClass1,派生類是SubClass
pass

class SubClass_two(ParentClass_one,ParentClass_two): #
python支持多繼承,用逗號分隔開多個繼承的類 pass

經典類與新式類

  • 只有在python2中才分新式類和經典類,python3中統一都是新式類
  • 在python2中,沒有顯式的繼承object類的類,以及該類的子類,都是經典類
  • 在python2中,顯式地聲明繼承object的類,以及該類的子類,都是新式類
  • 在python3中,無論是否繼承object,都默認繼承object,即python3中所有類均為新式類

繼承與抽象

  • 繼承描述的是子類與父類之間的關系,是一種什麽是什麽的關系。要找出這種關系,必須先抽象再繼承,抽象即抽取類似或者說比較像的部分。抽象最主要的作用是劃分類別(可以隔離關註點,降低復雜度)
  • 繼承是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象這個過程,才能通過繼承的方式去表達出抽象的結構。抽象只是分析和設計的過程中,一個動作或者說一種技巧,通過抽象可以得到類

繼承與重用性

在開發程序的過程中,如果我們定義了一個類A,然後又想新建立另外一個類B,但是類B的大部分內容與類A的相同時,則不需要從頭開始寫一個類B,只需要通過繼承的方式新建類B,讓B繼承A,B會‘遺傳’A的所有屬性(數據屬性和函數屬性),實現代碼重用

class Hero:
def __init__(self,nickname,aggressivity,life_value):
self.nickname=nickname
self.aggressivity
=aggressivity self.life_value=life_value def move_forward(self): print(%s move forward %self.nickname) def move_backward(self): print(%s move backward %self.nickname) def move_left(self): print(%s move forward %self.nickname) def move_right(self): print(%s move forward %self.nickname) def attack(self,enemy): enemy.life_value-=self.aggressivity class Garen(Hero): pass class Riven(Hero): pass g=Garen(草叢倫,100,300) r=Riven(銳雯雯,57,200) print(g.life_value) r1.attack(g) print(g.life_value) ‘‘‘ 運行結果 243 ‘‘‘ ps:像g.life_value之類的屬性引用,會先從實例中找life_value然後去類中找,然後再去父類中找...直到最頂級的父類。

派生

子類也可以添加自己新的屬性或者在自己這裏重新定義這些屬性(不會影響到父類),需要一旦重新定義了自己的屬性且與父類重名,那麽調用新增的屬性時,就以自己為準。

class Riven(Hero):
camp=Noxus
def __init__(self,nickname,aggressivity,life_value,skin):
Hero.__init__(self,nickname,aggressivity,life_value) #調用父類功能
self.skin=skin #新屬性
def attack(self,enemy): #在自己這裏定義新的attack,不再使用父類的attack,且不會影響父類
Hero.attack(self,enemy) #調用功能
print(from riven)
def fly(self): #在自己這裏定義新的
print(%s is flying %self.nickname)

r=Riven(銳雯雯,57,200,比基尼)
r.fly()
print(r.skin)

‘‘‘
運行結果
銳雯雯 is flying
比基尼

‘‘‘

組合與重用性

組合指的是,在一個類中以另外一個類的對象作為數據屬性,稱為類的組合

class Equip: #武器裝備類
def fire(self):
print(release Fire skill)

class Riven: #英雄Riven的類,一個英雄需要有裝備,因而需要組合Equip類
camp=Noxus
def __init__(self,nickname):
self.nickname=nickname
self.equip=Equip() #用Equip類產生一個裝備,賦值給實例的equip屬性

r=Riven(銳雯雯)
print(r.equip.fire()) #可以使用組合的類產生的對象所持有的方法

‘‘‘
release Fire skill
‘‘‘

組合與繼承

  • 繼承的方式:通過繼承建立了派生類與基類之間的關系,它是一種‘是‘的關系,比如白馬是馬,人是動物。當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老師是人,學生是人
  • 組合的方式:用組合的方式建立了類與組合的類之間的關系,它是一種‘有’的關系,比如教授有生日,教授教python和linux課程,教授有學生s1、s2、s3...

ps:當類之間有顯著不同,並且較小的類是較大的類所需要的組件時,使用組合比較好

class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex

class Course:
def __init__(self,name,period,price):
self.name=name
self.period=period
self.price=price
def tell_info(self):
print(<%s %s %s> %(self.name,self.period,self.price))

class Teacher(People):
def __init__(self,name,age,sex,job_title):
People.__init__(self,name,age,sex)
self.job_title=job_title
self.course=[]
self.students=[]


class Student(People):
def __init__(self,name,age,sex):
People.__init__(self,name,age,sex)
self.course=[]


jack=Teacher(jack,18,male,computer teacher)
s=Student(tom,18,female)

python=Course(python,3mons,3000.0)
linux=Course(python,3mons,3000.0)

#為老師jack和學生s1添加課程
jack.course.append(python)
jack.course.append(linux)
s.course.append(python)

#為老師jack添加學生s
jack.students.append(s)


#使用
for obj in jack.course:
obj.tell_info()

繼承實現原理

在Java和C#中子類只能繼承一個父類,而Python中子類可以同時繼承多個父類,如A(B,C,D),如果繼承關系為非菱形結構,則會按照先找B這一條分支,然後再找C這一條分支,最後找D這一條分支的順序直到找到我們想要的屬性,如果繼承關系為菱形結構,那麽屬性的查找方式有兩種,分別是:深度優先和廣度優先
技術分享圖片

技術分享圖片

def test(self):
print(from A)

class B(A):
def test(self):
print(from B)

class C(A):
def test(self):
print(from C)

class D(B):
def test(self):
print(from D)

class E(C):
def test(self):
print(from E)

class F(D,E):
# def test(self):
# print(‘from F‘)
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有這個屬性可以查看線性列表,經典類沒有這個屬性

#新式類繼承順序:F->D->B->E->C->A
#經典類繼承順序:F->D->B->A->E->C
#python3中統一都是新式類
#pyhon2中才分新式類與經典類

Python實現繼承

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‘>],為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條準則:

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

子類調用父類的方法
方法一:指名道姓,即父類名.父類方法()

class Vehicle: #定義交通工具類
Country=China
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power

def run(self):
print(開動啦...)

class Subway(Vehicle): #地鐵
def __init__(self,name,speed,load,power,line):
Vehicle.__init__(self,name,speed,load,power)
self.line=line

def run(self):
print(地鐵%s號線歡迎您 %self.line)
Vehicle.run(self)

line13=Subway(中國地鐵,180m/s,1000人/箱,,13)
line13.run()、

方法二:super()

class Vehicle: #定義交通工具類
Country=China
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power

def run(self):
print(開動啦...)

class Subway(Vehicle): #地鐵
def __init__(self,name,speed,load,power,line):
#super(Subway,self) 就相當於實例本身 在python3中super()等同於super(Subway,self)
super().__init__(name,speed,load,power)
self.line=line

def run(self):
print(地鐵%s號線歡迎您 %self.line)
super(Subway,self).run()

class Mobike(Vehicle):#摩拜單車
pass

line13=Subway(中國地鐵,180m/s,1000人/箱,,13)
line13.run()

python-繼承與重用