面向物件:類空間問題以及類之間的關係
一. 類的空間問題
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中類的實現關係和類的繼承是一個意