2.面向對象:類空間問題以及類之間的關係
- 2019 年 10 月 3 日
- 筆記
一. 類的空間問題
1.1 何處可以添加對象屬性
class A: def __init__(self,name): self.name = name def func(self,sex): self.sex = sex
# 類外面可以: obj = A('barry') obj.age = 18 print(obj.__dict__) # {'name': 'barry', 'age': 18} # 類內部也可以: obj = A('barry') # __init__方法可以。 obj.func('男') # func 方法也可以。
**總結:對象的屬性不僅可以在__init__裡面添加,還可以在類的其他方法或者類的外面添加。**
1.2 何處可以添加類的靜態屬性
class A: def __init__(self,name): self.name = name def func(self,sex): self.sex = sex def func1(self): A.bbb = 'ccc'
# 類的外部可以添加 A.aaa = 'taibai' print(A.__dict__) # 類的內部也可以添加。 A.func1(111) print(A.__dict__)
總結:類的屬性不僅可以在類內部添加,還可以在類的外部添加。
1.3 對象如何找到類的屬性
之前咱們都學習過,實例化一個對象,可以通過點的方式找到類中的屬性,那麼他為什麼可以找到類中的屬性呢?
通過圖解說明:
對象查找屬性的順序:先從對象空間找 ——> 類空間找 ——> 父類空間找 ——->…..
類名查找屬性的順序:先從本類空間找 ——-> 父類空間找——–> ……..
上面的順序都是單向不可逆,類名不可能找到對象的屬性。
二. 類與類之間的關係
⼤千世界, 萬物之間皆有規則和規律. 我們的類和對象是對⼤千世界中的所有事物進⾏歸類. 那事物之間存在著相對應的關係. 類與類之間也同樣如此. 在⾯向對象的世界中. 類與類中存在以下關係:
1. 依賴關係
2. 關聯關係
3. 組合關係
4. 聚合關係
5. 實現關係
6. 繼承關係(類的三大特性之一:繼承。)
2.1 依賴關係
⾸先, 我們設計⼀個場景. 還是最初的那個例⼦. 要把⼤象裝冰箱. 注意. 在這個場景中, 其實是存在了兩種事物的. ⼀個是⼤象, ⼤象負責整個事件的掌控者, 還有⼀個是冰箱, 冰箱負責被⼤象操縱.
⾸先, 寫出兩個類, ⼀個是⼤象類, ⼀個是冰箱類
class Elphant: def __init__(self, name): self.name = name def open(self): ''' 開⻔ ''' pass def close(self): ''' 關⻔ ''' pass class Refrigerator: def open_door(self): print("冰箱⻔被打開了") def close_door(self): print("冰箱⻔被關上了")
冰箱的功能非常簡單, 只要會開⻔, 關⻔就⾏了. 但是⼤象就沒那麼簡單了. 想想. ⼤象開⻔和關⻔的時候是不是要先找個冰箱啊. 然後呢? 打開冰箱⻔. 是不是打開剛才找到的那個冰箱⻔. 然後裝⾃⼰. 最後呢? 關冰箱⻔, 注意, 關的是剛才那個冰箱吧. 也就是說. 開⻔和關⻔⽤的是同⼀個冰箱. 並且. ⼤象有更換冰箱的權利, 想進那個冰箱就進那個冰箱. 這時, ⼤象類和冰箱類的關係並沒有那麼的緊密. 因為⼤象可以指定任何⼀個冰箱. 接下來. 我們把程式碼完善⼀下.
class Elphant: def __init__(self, name): self.name = name def open(self,obj1): ''' 開⻔ ''' print('大象要開門了,默念三聲,開') obj1.open_door() def close(self): ''' 關⻔ ''' print('大象要關門了,默念三聲,關') class Refrigerator: def open_door(self): print("冰箱⻔被打開了") def close_door(self): print("冰箱⻔被關上了") elphant1 = Elphant('大象') haier = Refrigerator() elphant1.open(haier)
動作發起的主體是大象,你們把關門這個練一下。依賴關係:將一個類的對象或者類名傳到另一個類的方法使用。此時, 我們說, ⼤象和冰箱之間就是依賴關係. 我⽤著你. 但是你不屬於我. 這種關係是最弱的.比如. 公司和僱員之間. 對於正式員⼯, 肯定要簽訂勞動合約. 還得⼩⼼伺候著. 但是如果是兼職. 那⽆所謂. 需要了你就來. 不需要你就可以拜拜了. 這⾥的兼職(臨時⼯) 就屬於依賴關係.我⽤你. 但是你不屬於我
2.2 關聯,聚合,組合關係
其實這三個在程式碼上寫法是⼀樣的. 但是, 從含義上是不⼀樣的.
1. 關聯關係. 兩種事物必須是互相關聯的. 但是在某些特殊情況下是可以更改和更換的.
2. 聚合關係. 屬於關聯關係中的⼀種特例. 側重點是xxx和xxx聚合成xxx. 各⾃有各⾃的聲明周期. 比如電腦. 電腦⾥有CPU, 硬碟, 記憶體等等. 電腦掛了. CPU還是好的. 還是完整的個體
3. 組合關係. 屬於關聯關係中的⼀種特例. 寫法上差不多. 組合關係比聚合還要緊密. 比如⼈的⼤腦, ⼼臟, 各個器官. 這些器官組合成⼀個⼈. 這時. ⼈如果掛了. 其他的東⻄也跟著掛了
先看關聯關係:
這個最簡單. 也是最常⽤的⼀種關係. 比如. ⼤家都有男女朋友. 男⼈關聯著女朋友. 女⼈關聯著男朋友. 這種關係可以是互相的, 也可以是單⽅⾯的.
class Boy: def __init__(self,name,girlFriend=None): self.name = name self.girlFriend = girlFriend def have_a_diner(self): if self.girlFriend: print('%s 和 %s 一起晚飯'%(self.name,self.girlFriend.name)) else: print('單身狗,吃什麼飯') class Girl: def __init__(self,name): self.name = name
b = Boy('日天') b.have_a_diner() # 此時是單身狗 # 突然有一天,日天牛逼了 b.girlFriend = '如花' b.have_a_diner() #共進晚餐
# wusir 生下來就有女朋友 服不服 gg = Girl('小花') bb = Boy('wusir', gg) bb.have_a_diner() # 結果嫌他有點娘,不硬,分了 bb.girlFriend = None bb.have_a_diner()
注意. 此時Boy和Girl兩個類之間就是關聯關係. 兩個類的對象緊密練習著. 其中⼀個沒有了. 另⼀個就孤單的不得了. 關聯關係, 其實就是 我需要你. 你也屬於我. 這就是關聯關係. 像這樣的關係有很多很多. 比如. 學校和老師之間的關係.
# 老師屬於學校,必須有學校才可以工作 class School: def __init__(self,name,address): self.name = name self.address = address class Teacher: def __init__(self,name,school): self.name = name self.school = school s1 = School('北京校區','美麗的沙河') s2 = School('上海校區','上海迪士尼旁邊') s3 = School('深圳校區','南山區') t1 = Teacher('武大',s1) t2 = Teacher('海峰',s2) t3 = Teacher('日天',s3) print(t1.school.name) print(t2.school.name) print(t3.school.name)
但是學校也是依賴於老師的,所以老師學校應該互相依賴。
class School: def __init__(self,name,address): self.name = name self.address = address self.teacher_list = [] def append_teacher(self,teacher): self.teacher_list.append(teacher) class Teacher: def __init__(self,name,school): self.name = name self.school = school s1 = School('北京校區','美麗的沙河') s2 = School('上海校區','上海迪士尼旁邊') s3 = School('深圳校區','南山區') t1 = Teacher('武大',s1) t2 = Teacher('海峰',s2) t3 = Teacher('日天',s3) s1.append_teacher(t1) s1.append_teacher(t2) s1.append_teacher(t3) # print(s1.teacher_list) # for teacher in s1.teacher_list: # print(teacher.name)
好了. 這就是關聯關係. 當我們在邏輯上出現了. 我需要你. 你還得屬於我. 這種邏輯 就是關聯關係. 那注意. 這種關係的緊密程度比上⾯的依賴關係要緊密的多. 為什麼呢? 想想吧
至於組合關係和聚合關係,其實程式碼上差別不大,咱們就以組合舉例:
組合:將一個類的對象封裝到另一個類的對象的屬性中,就叫組合。
咱們設計一個遊戲人物類,讓實例化幾個對象讓這幾個遊戲人物實現互毆的效果。
class Gamerole: def __init__(self,name,ad,hp): self.name = name self.ad = ad self.hp = hp def attack(self,p1): p1.hp -= self.ad print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp)) gailun = Gamerole('蓋倫',10,200) yasuo= Gamerole('亞索',50,80) #蓋倫攻擊亞索 gailun.attack(yasuo) # 亞索攻擊蓋倫 yasuo.attack(蓋倫)
但是這樣互相攻擊沒有意思,一般遊戲類的的對戰方式要藉助武器,武器是一個類,武器類包含的對象很多:刀槍棍劍斧鉞鉤叉等等,所以咱們要寫一個武器類。
class Gamerole: def __init__(self,name,ad,hp): self.name = name self.ad = ad self.hp = hp def attack(self,p1): p1.hp -= self.ad print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp)) class Weapon: def __init__(self,name,ad): self.name = name self.ad = ad def weapon_attack(self,p1,p2): p2.hp = p2.hp - self.ad - p1.ad print('%s 利用 %s 攻擊了%s,%s還剩%s血' %(p1.name,self.name,p2.name,p2.name,p2.hp))
接下來藉助武器攻擊對方:
pillow = Weapon('繡花枕頭',2) pillow.weapon_attack(barry,panky) # 但是上面這麼做不好,利用武器攻擊也是人類是動作的發起者,所以不能是pillow武器對象,而是人類利用武器攻擊對方
所以,對程式碼進行修改。
class Gamerole: def __init__(self,name,ad,hp): self.name = name self.ad = ad self.hp = hp def attack(self,p1): p1.hp -= self.ad print('%s攻擊%s,%s掉了%s血,還剩%s血'%(self.name,p1.name,p1.name,self.ad,p1.hp)) def equip_weapon(self,wea): self.wea = wea # 組合:給一個對象封裝一個屬性改屬性是另一個類的對象 class Weapon: def __init__(self,name,ad): self.name = name self.ad = ad def weapon_attack(self,p1,p2): p2.hp = p2.hp - self.ad - p1.ad print('%s 利用 %s 攻擊了%s,%s還剩%s血' %(p1.name,self.name,p2.name,p2.name,p2.hp)) # 實例化三個人物對象: barry = Gamerole('太白',10,200) panky = Gamerole('金蓮',20,50) pillow = Weapon('繡花枕頭',2) # 給人物裝備武器對象。 barry.equip_weapon(pillow) # 開始攻擊 barry.wea.weapon_attack(barry,panky)
上面就是組合,只要是人物.equip_weapon這個方法,那麼人物就封裝了一個武器對象,再利用武器對象調用其類中的weapon_attack方法。
在python中類的實現關係和類的繼承是一個意思