今天整理類的組合以及類的三大特性python
1.類的組合程序員
2.類的繼承算法
3.類的封裝python3.x
4.類的多態app
開始今日份整理函數
1.類的組合測試
類與類之間,並非獨立的,不少的時候在正常使用的時候都是類與類之間互相調用,因此就須要對類與類之間的關聯或者是聯繫進行整理一下,就拿以前的英雄聯盟的遊戲人物之間的關係舉例。ui
1.1類的組合spa
在定義lol中不一樣的英雄人物,那麼正常遊戲過程當中,是須要使用武器等,這個時候就用到了組合,查看代碼code
class Game_role(): def __init__(self,name,ad,hp): self.name = name self.ad = ad self.hp = hp def attack(self,obj): obj.hp -= self.ad print('{}打了{}一次,{}丟失{}點血量,如今血量爲{}'.format(self.name,obj.name,obj.name,self.ad,obj.hp)) def equip_weapon(self,obj): self.weapon = obj class Weapon(): def __init__(self,name,ad): self.name = name self.ad = ad def attack_weapon(self,obj1,obj2): obj2.hp -=(self.ad+obj1.ad) print('{}用{}打了{}一下,{}還剩{}點血量'.format(obj1.name,self.name,obj2.name,obj2.name,obj2.hp)) r1 = Game_role('蓋倫',15,200) r2 = Game_role('劍姬',30,140) w1 = Weapon('三相',20) r1.equip_weapon(w1) r1.weapon.attack_weapon(r1,r2) #結果 蓋倫用三相打了劍姬一下,劍姬還剩105點血量
這個算最基本的類之間的組合,對於類的組合,其實就是給一個對象封裝一個屬性,而這個屬性是另一個對象,也是最low的了。不過類的組合也是有好處的
一些小的測試題
1,暴力摩托程序(完成下列需求): 1.1建立三個遊戲人物,分別是: • 蒼井井,女,18,攻擊力ad爲20,血量200 • 東尼木木,男,20,攻擊力ad爲30,血量150 • 波多多,女,19,攻擊力ad爲50,血量80 1.2建立三個遊戲武器,分別是: • 平底鍋,ad爲20 • 斧子,ad爲50 • 雙節棍,ad爲65 1.3 建立三個遊戲摩托車,分別是: • 小踏板,速度60邁 • 雅馬哈,速度80邁 • 寶馬,速度120邁。 完成下列需求(利用武器打人掉的血量爲武器的ad + 人的ad): (1)蒼井井騎着小踏板開着60邁的車行駛在賽道上。 (2)東尼木木騎着寶馬開着120邁的車行駛在賽道上。 (3)波多多騎着雅馬哈開着80邁的車行駛在賽道上。 (4)蒼井井赤手空拳打了波多多20滴血,波多多還剩xx血。 (5)東尼木木赤手空拳打了波多多30滴血,波多多還剩xx血。 (6)波多多利用平底鍋打了蒼井井一平底鍋,蒼井井還剩xx血。 (7)波多多利用斧子打了東尼木木一斧子,東尼木木還剩xx血。 (8)蒼井井騎着寶馬打了騎着小踏板的東尼木木一雙節棍,東尼木木哭了,還剩xx血。(選作) (9)波多多騎着小踏板打了騎着雅馬哈的東尼木木一斧子,東尼木木哭了,還剩xx血。
1.2類的依賴
類的依賴:給一個類的方法傳了一個參數,而這個參數是一個類的對象,這種依賴關係是關係中緊密型最低的,耦合性最低的,就像上面的lol中人自身的攻擊手段,他調用的是對方的對象,這個時候蓋倫中有劍姬,而劍姬沒有蓋倫,並非像武器,武器已經徹底變成蓋倫的屬性而存在,緊密結合。用大象關冰箱來作一個測試。
class Elephant(): def __init__(self,name): self.name = name def open_door(self,obj): print('1,2,3,開門') obj.open_() def close_door(self,obj): print('3,2,1,關門 ') obj.close_() class Refrigerator(): def __init__(self,name): self.name = name def open_(self): print('門正在打開') def close_(self): print('門正在關閉') e1 = Elephant('神奇的大象') r1 = Refrigerator('海爾') e1.open_door(r1) e1.close_door(r1)
和上面的相比,此次對象一樣調用了另外的obj,但是隻是使用了方法,並無讓obj成爲本身的屬性
1.3類的關聯,聚合關係,組合關係
其實這個關係仍是組合,仍是舉倆個例子吧,一個陪女朋友吃飯,一個是教師關聯學校
陪女朋友吃飯
class Boy(): def __init__(self,name,girelfriend=None): self.name = name self.girlfrind = girelfriend def have_dinner(self): if self.girlfrind == None: print('單身狗,吃啥吃!') else: print('%s 與%s共進晚餐'%(self.name,self.girlfrind.name)) def get_girlfrind(self,obj): self.girlfrind = obj def lose_girlfriend(self): self.girlfrind = None class Girl(): def __init__(self,name): self.name = name b1 = Boy('屌絲')#無女朋友 g1 = Girl('美女') b2 = Boy('小哥',g1)#有娃娃親 b1.have_dinner() b2.have_dinner()
教師關聯學校
class School(): def __init__(self,city,address): self.city = city self.address = address self.teacher_list = [] class Teacher(): def __init__(self,name,language): self.name = name self.language = language self.school = None def binding(self,li): for i,j in enumerate(li): print(i,'學校所在地址爲%s'%j.city) choice = int(input('你所選擇的學校的序號>>>').strip()) self.school = li[choice]#教師綁定了學校 li[choice].teacher_list.append(self)#學校綁定了教師 print('學校綁定教師成功') school1 =School('北京','昌平') school2 =School('上海','張江') li = [school1,school2] test1 =Teacher('alex','python') test1.binding(li) for i in school1.teacher_list: print(i.name,i.language)
2.類的繼承
就像人和狗都屬於動物,人和狗都有年齡啊什麼的共同方法,那麼咱們就能夠寫一個公共類,狗和人繼承好了
class Animal: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def eat(self): print('在吃東西') class People(Animal): def __init__(self,name,age,sex,skin): #方式一 Animal.__init__(self,name,age,sex) #方式二 super().__init__(name,age,sex) self.skin = skin def eat(self): print('人在吃東西') #對於狗也是同樣
2.1類的單繼承
類的單繼承就是字面意思,一個類只有一個父類用於繼承,父類又稱之爲基類或者是超類,子類又稱之爲派生類
就像上面的例子,people類繼承了animal類,people類可使用父類的屬性以及方法。
查看子類的繼承狀況爲:print(類.__base__)
# 既要執行子類方法,又要執行父類方法 # 方法一: Aniaml.__init__(self,name,sex,age) # p1 = Person('春哥','laddboy',18,'有思想') # print(p1.__dict__) # 方法二:super # p1 = Person('春哥','laddboy',18,'有思想') # print(p1.__dict__) # def func(self): # pass # self = 3 # func(self) # p1 = Person('春哥','laddboy',18,'有思想') # p1.eat()
對於單繼承就是這樣了。
2.2類的多繼承
類的多繼承能夠這麼理解,就是一個兒子有多個爹,而後類的繼承就須要排序了。對於類的分類,主要有經典類與新式類倆種
經典類的查詢,如圖,就是一條道走到黑
新式類的查詢,採用c3算法
c3算法:# #mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
下面是推倒過程
# #mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) mro(K(H,I)) =[K]+merge(mro(H),mro(I),[H,I]) mro(H(E,F)) = [H] +merge(mro(E),mro(F),[E,F]) mro(E(B,C)) = [E] +merge([B,A],[C,A],[B,C]) mro(E(B,C)) = [E,B] +merge([A],[C,A],[C]) mro(E(B,C)) = [E,B,C,A] mro(F(C,D)) = [F] +merge([C,A],[D,A],[C,D]) mro(F(C,D)) = [F,C] +merge([A],[D,A],[D]) mro(F(C,D)) = [F,C,D,A] mro(H(E,F)) = [H] +merge([E,B,C,A],[F,C,D,A],[E,F]) mro(H(E,F)) = [H,E] +merge([B,C,A],[F,C,D,A],[F]) mro(H(E,F)) = [H,E,B] +merge([C,A],[F,C,D,A],[F]) mro(H(E,F)) = [H,E,B,F] +merge([C,A],[C,D,A]) mro(H(E,F)) = [H,E,B,F,C,] +merge([A],[D,A]) mro(H(E,F)) = [H,E,B,F,C,D,A] mro(I(F,G)) =[I] +merge(mro(F),mro(G),[F,G]) mro(F(C,D)) = [F] +merge(mro[C],mro[D],[C,D]) mro(F(C,D)) = [F] +merge([C,A],D,A,[C,D]) mro(F(C,D)) = [F,C] +merge([A],D,A,[D]) mro(F(C,D)) = [F,C,D,A] mro(G)=[D,A] mro(I(F,G)) =[I] +merge([F,C,D,A],[G,D,A],[F,G]) mro(I(F,G)) =[I,F] +merge([C,D,A],[G,D,A],[G]) mro(I(F,G)) =[I,F,C] +merge([D,A],[G,D,A],[G]) mro(I(F,G)) =[I,F,C,G] +merge([D,A],[D,A]) mro(I(F,G)) =[I,F,C,G,D,A] mro(K(H,I)) =[K]+merge([H,E,B,F,C,D,A],[I,F,C,G,D,A],[H,I]) mro(K(H,I)) =[K,H]+merge([E,B,F,C,D,A],[I,F,C,G,D,A],[I]) mro(K(H,I)) =[K,H,E,B,I]+merge([F,C,D,A],[F,C,G,D,A]) mro(K(H,I)) =[K,H,E,B,I,F,C]+merge([D,A],[G,D,A]) mro(K(H,I)) =[K,H,E,B,I,F,C,G,D,A] #最後的執行順序就是[K,H,E,B,I,F,C,G,D,A]
若是不用這種手算的推導式,其實能夠直接調用方法查看
print(K.__mro__)
#結果和上面是一致的
super()也是按照上面的c3算法來調用的
根據上面作一些派生
子類能夠添加本身新的屬性或者在本身這裏定義這些屬性(不會影響父類),須要注意的是,一旦從新定義了與父類相同的名字的屬性,會以本身爲準。
在子類中,新建的重名函數類型,在編輯函數功能時,有可能調用父類的相同名字的函數功能時,應該用普通函數方法同樣,所以即便是self也應該傳值進去,例如類名.func(參數)
繼承原理:
3.類的封裝
在講類的封裝的前提須要說一下類方法的隱藏
3.1隱藏
類的結構中能夠分靜態屬性以及動態屬性,按照另一個角度,能夠劃分爲公有,私有屬性
class Boss(): name = 'alex' __secretary =['女一','男二','野模']#私有靜態屬性 def __init__(self,username,password): self.username = username self.__password = password#私有對象屬性 def func(self): print('老闆在辦公') def __func1(self): print('老闆在和祕書辦公')#私有方法 def print(self): print(self.__secretary) self.__func1() b1 = Boss('alex',123) print(b1.name) #print(b1.__secretary) b1.print()
咱們會發現,按照之前的同樣的調用方法,根本得不到這些私有屬性以及私有方法,若是咱們在類內定義一個函數專門用於調用這些私有方法,才能看到這些私有屬性,單獨的去調用這些私有屬性只會報錯沒有這些方法,咱們會發現只有類的內部才能調用,類的外部以及派生類根本沒法調用屬性。
不過並非徹底沒法調用,當咱們看類的__dict__方法時,咱們會發現,python對類內部這些私有方法屬性進行了包裝
{'_Boss__secretary': ['女一', '男二', '野模'], '__doc__': None, '__init__': <function Boss.__init__ at 0x016246A8>, 'name': 'alex', '_Boss__func1': <function Boss.__func1 at 0x016D40C0>, 'print': <function Boss.print at 0x016D4078>, '__weakref__': <attribute '__weakref__' of 'Boss' objects>, '__dict__': <attribute '__dict__' of 'Boss' objects>, 'func': <function Boss.func at 0x016D4030>, '__module__': '__main__'}
咱們採用_boss__password這樣的形式仍是能夠調用的。不過通常不建議這麼使用,變形後的注意問題
3.2封裝的意義
封裝的意義爲
3.3propetry函數
propetry也叫作類的私有屬性
class Market(): def __init__(self,name,prix,discount): self.name = name self.__prix = prix self.__discount = discount @property#設定爲私有方法 def price(self): return self.__prix*self.__discount @price.setter#對私有方法的內容進行修改 def price(self,new_price): self.__prix = new_price @price.deleter#對私有方法的內容進行刪除,不過不是常常用 def price(self): del self.__prix m1 = Market('洗髮水',45,0.8) print(m1.price) m1.price = 48 print(m1.price) del m1.price print(m1.price)
將一個類的方法修改成私有方法,這樣就假裝成屬性,雖然在代碼邏輯上沒有什麼提升,可是會讓執行起來更合理一些,
4.類的多態
多態指的是一類事物有多種形態,好比:動物有多種形態:人,狗,豬
import abc class Animal(metaclass=abc.ABCMeta): #同一類事物:動物 @abc.abstractmethod def talk(self): pass class People(Animal): #動物的形態之一:人 def talk(self): print('say hello') class Dog(Animal): #動物的形態之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #動物的形態之三:豬 def talk(self): print('say aoao')
4.1類的多態性
多態性是指在不考慮實例類型的狀況下使用實例,多態性分爲靜態多態性和動態多態性
靜態多態性:如任何類型均可以用運算符+進行運算
動態多態性:以下
peo=People() dog=Dog() pig=Pig() #peo、dog、pig都是動物,只要是動物確定有talk方法 #因而咱們能夠不用考慮它們三者的具體是什麼類型,而直接使用 peo.talk() dog.talk() pig.talk() #更進一步,咱們能夠定義一個統一的接口來使用 def func(obj): obj.talk()
其實你們從上面多態性的例子能夠看出,咱們並無增長什麼新的知識,也就是說python自己就是支持多態性的,這麼作的好處是什麼呢?
4.2鴨子方法
Python崇尚鴨子類型,即‘若是看起來像、叫聲像並且走起路來像鴨子,那麼它就是鴨子’
python程序員一般根據這種行爲來編寫程序。例如,若是想編寫現有對象的自定義版本,能夠繼承該對象
也能夠建立一個外觀和行爲像,但與它無任何關係的全新對象,後者一般用於保存程序組件的鬆耦合度。
例1:利用標準庫中定義的各類‘與文件相似’的對象,儘管這些對象的工做方式像文件,但他們沒有繼承內置文件對象的方法
#兩者都像鴨子,兩者看起來都像文件,於是就能夠當文件同樣去用 class TxtFile: def read(self): pass def write(self): pass class DiskFile: def read(self): pass def write(self): pass