1. 程式人生 > >python D17 類與類之間的關係

python D17 類與類之間的關係

# 類與類之間的關係
# 1、以來關係
# 2、關聯關係、組合關係、聚合關係
# 3、繼承關係,self到底是什麼鬼?
# 4、類中的特殊成員

# 一、類與類之間的以來關係
# ⼤千世界, 萬物之間皆有規則和規律. 我們的類和物件是對⼤千世界中的所有事物進⾏歸
# 類. 那事物之間存在著相對應的關係. 類與類之間也同樣如此. 在⾯向物件的世界中. 類與類
# 中存在以下關係:
# 1. 依賴關係
# 2. 關聯關係
# 3. 組合關係
# 4. 聚合關係
# 5. 繼承關係
# 6. 實現關係
# 由於python是⼀⻔弱型別程式設計語⾔. 並且所有的物件之間其實都是多型的關係. 也就是說,
# 所有的東⻄都可以當做物件來使⽤. 所以我們在寫程式碼的時候很容易形成以上關係. ⾸先. 我
# 們先看第⼀種, 也是這些關係中緊密程度最低的⼀個, 依賴關係.

# ⾸先, 我們設計⼀個場景. 還是最初的那個例⼦. 要把⼤象裝冰箱. 注意. 在這個場景中, 其
# 實是存在了兩種事物的. ⼀個是⼤象, ⼤象負責整個事件的掌控者, 還有⼀個是冰箱, 冰箱負
# 責被⼤象操縱.
# ⾸先, 寫出兩個類, ⼀個是⼤象類, ⼀個是冰箱類.
# class Elphant:
# def __init__(self, name):
# self.name = name
# def open(self):
# '''
# 開⻔
# :return :return:
# '''
# pass
# def close(self):
# '''
# 關⻔
# :return :return:
# '''
# pass
#
# class Refrigerator:
# def open_door(self):
# print("冰箱⻔被打開了")
#
# def close_door(self):
# print("冰箱⻔被關上了")
# 冰箱的功能非常簡單, 只要會開⻔, 關⻔就⾏了. 但是⼤象就沒那麼簡單了. 想想. ⼤象開
# ⻔和關⻔的時候是不是要先找個冰箱啊. 然後呢? 開啟冰箱⻔. 是不是開啟剛才找到的那個冰
# 箱⻔. 然後裝⾃⼰. 最後呢? 關冰箱⻔, 注意, 關的是剛才那個冰箱吧. 也就是說. 開⻔和關⻔
# ⽤的是同⼀個冰箱. 並且. ⼤象有更換冰箱的權利, 想進那個冰箱就進那個冰箱. 這時, ⼤象類
# 和冰箱類的關係並沒有那麼的緊密. 因為⼤象可以指定任何⼀個冰箱. 接下來. 我們把程式碼完
# 善⼀下.

# class Elphan:
# def __init__(self, name):
# self.name = name
# def open(self, ref):
# print("⼤象要開⻔了. 默唸三聲. 開!")
# # 由外界傳遞進來⼀個冰箱, 讓冰箱開⻔. 這時. ⼤象不⽤揹著冰箱到處跑.
# # 類與類之間的關係也就不那麼的緊密了. 換句話說. 只要是有open_door()⽅法的物件. 都可以接收運⾏
# ref.open_door()
#
# def close(self, ref):
# print("⼤象要關⻔了. 默唸三聲. 關!")
# ref.close_door()
# def take(self):
# print("鑽進去")
#
# class Refrigerator:
# def open_door(self):
# print("冰箱⻔被打開了")
# def close_door(self):
# print("冰箱⻔被關上了")
#
# # 造冰箱
# r = Refrigerator()
# # 造⼤象
# el = Elphan("神奇的⼤象")
# el.open(r) # 注意. 此時是把⼀個冰箱作為引數傳遞進去了. 也就是說. ⼤象可以指定任何⼀個冰箱.
# el.take()
# el.close(r)
# 此時, 我們說, ⼤象和冰箱之間就是依賴關係. 我⽤著你. 但是你不屬於我. 這種關係是最弱的.
# 比如. 公司和僱員之間. 對於正式員⼯, 肯定要簽訂勞動合同. 還得⼩⼼伺候著. 但是如果是兼
# 職. 那⽆所謂. 需要了你就來. 不需要你就可以拜拜了. 這⾥的兼職(臨時⼯) 就屬於依賴關係.
# 我⽤你. 但是你不屬於我.

# ⼆. 關聯關係.組合關係, 聚合關係
# 其實這三個在程式碼上寫法是⼀樣的. 但是, 從含義上是不⼀樣的.
# 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_dinner(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("alex")
# b.have_a_dinner()
# # 突然⽜B了. 找到⼥朋友了
# g = Girl("如花")
# b.girlFriend = g # 有⼥朋友了. 6666
# b.have_a_dinner()
# gg = Girl("李⼩花")
# bb = Boy("wusir", gg) # 娃娃親. 出⽣就有⼥朋友. 服不服
# bb.have_a_dinner() # 多麼幸福的⼀家
# # 突然.bb失戀了. 娃娃親不跟他好了
# bb.girlFriend = None
# bb.have_a_dinner() # ⼜單身了.

# 注意. 此時Boy和Girl兩個類之間就是關聯關係. 兩個類的物件緊密練習著. 其中⼀個沒有
# 了. 另⼀個就孤單的不得了. 關聯關係, 其實就是 我需要你. 你也屬於我. 這就是關聯關係. 像
# 這樣的關係有很多很多. 比如. 學校和老師之間的關係.

# School --- 學校
# Teacher--- 老師
# 老師必然屬於⼀個學校. 換句話說. 每個老師肯定有⼀個指定的⼯作機構. 就是學校. 那老師
# 的屬性中必然關聯著學校.
# 一個老師對應一個學校 站在老師這個物件上
# class School:
# def __init__(self, name, address):
# self.name = name
# self.address = address
# class Teacher:
# def __init__(self, name, school=None):
# self.name = name
# self.school = school
# s1 = School("⽼男孩北京校區", "美麗的沙河")
# s2 = School("⽼男孩上海校區", "迪⼠尼旁邊")
# s3 = School("⽼男孩深圳校區", "南⼭區法院歡迎你")
# t1 = Teacher("⾦王", s1)
# t2 = Teacher("銀王", s1)
# t3 = Teacher("海峰", s2)
# t4 = Teacher("⾼鑫", s3)
# # 找到⾼鑫所在的校區地址
# print(t4.school.address)

# 想想, 這樣的關係如果反過來. ⼀個老師可以選⼀個學校任職, 那反過來. ⼀個學校有多少
# 老師呢? ⼀堆吧? 這樣的關係如何來描述呢?
# 一個學校對應對個老師 一個老師對應一個學校 站在學校這個物件上
# class School:
# def __init__(self, name, address):
# self.name = name
# self.address = address
# self.t_list = [] # 每個學校都應該有⼀個裝⼀堆⽼師的列表
# def add_teacher(self, teacher):
# self.t_list.append(teacher)
# class Teacher:
# def __init__(self, name, school=None):
# self.name = name
# self.school = school
# s1 = School("⽼男孩北京校區", "美麗的沙河")
# s2 = School("⽼男孩上海校區", "迪⼠尼旁邊")
# s3 = School("⽼男孩深圳校區", "南⼭區法院歡迎你")
# t1 = Teacher("⾦王", s1)
# t2 = Teacher("銀王", s1)
# t3 = Teacher("海峰", s2)
# t4 = Teacher("⾼鑫", s3)
# s1.add_teacher(t1)
# s1.add_teacher(t2)
# s1.add_teacher(t3)
# # 檢視沙河校區有哪些⽼師
# for t in s1.t_list:
# print(t.name)

# 好了. 這就是關聯關係. 當我們在邏輯上出現了. 我需要你. 你還得屬於我. 這種邏輯 就是關
# 聯關係. 那注意. 這種關係的緊密程度比上⾯的依賴關係要緊密的多. 為什麼呢? 想想吧
# ⾄於組合關係和聚合關係. 其實程式碼上的差別不⼤. 都是把另⼀個類的物件作為這個類的
# 屬性來傳遞和儲存. 只是在含義上會有些許的不同⽽已.

# 三. 繼承關係.
# 在⾯向物件的世界中存在著繼承關係. 我們現實中也存在著這樣的關係. 我們說過. x是⼀
# 種y, 那x就可以繼承y. 這時理解層⾯上的. 如果上升到程式碼層⾯. 我們可以這樣認為. ⼦類在不
# 影響⽗類的程式運⾏的基礎上對⽗類進⾏的擴充和擴充套件. 這⾥.我們可以把⽗類被稱為超類或
# 者基類. ⼦類被稱為派⽣類.
# ⾸先, 類名和物件預設是可以作為字典的key的

# class Foo:
# def __init__(self):
# pass
# def method(self):
# pass
# # __hash__ = None
# print(hash(Foo))
# print(hash(Foo()))

# 既然可以hash. 那就是說字典的key可以是物件或者類
# dic = {}
# dic[Foo] = 123
# dic[Foo()] = 456
# print(dic) # {<class '__main__.Foo'>: 123, <__main__.Foo object at
# 0x103491550>: 456}

# 雖然顯⽰的有點⼉詭異. 但是是可以⽤的.
# 接下來. 我們來繼續研究繼承上的相關內容. 在本節中主要研究⼀下self. 記住. 不管⽅法之
# 間如何進⾏調⽤. 類與類之間是何關係. 預設的self都是訪問這個⽅法的物件.

# class Base:
# def __init__(self, num):
# self.num = num
# def func1(self):
# print(self.num)
# self.func2()
# def func2(self):
# print(111, self.num)
# class Foo(Base):
# def func2(self):
# print(222, self.num)
# lst = [Base(1), Base(2), Foo(3)]
# for obj in lst:
# obj.func1() # 那筆來吧. 好好算
# 結果
# 1,
# 111,1
# 2,
# 222,2
# 3,
# 222, 3
# 結論: self就是你訪問⽅法的那個物件. 先找⾃⼰, 然後在找⽗類的.

# 四.類中的特殊成員
# 什麼是特殊成員呢? __init_()
# 就是⼀個特殊的成員.說⽩了.帶雙下劃線的那⼀坨.這些⽅
# 法在特殊的場景的時候會被⾃動的執⾏.比如,

# 1. 類名() 會⾃動執⾏__init__()
# 2. 物件() 會⾃動執⾏__call__()
# 3. 物件[key] 會⾃動執⾏__getitem__()
# 4. 物件[key] = value 會⾃動執⾏__setitem__()
# 5. del 物件[key] 會⾃動執⾏ __delitem__()
# 6. 物件+物件 會⾃動執⾏ __add__()
# 7. with 物件 as 變數 會⾃動執⾏__enter__ 和__exit__
# 8. 列印物件的時候 會⾃動執⾏ __str__
# 9. ⼲掉可雜湊 __hash__ == None 物件就不可雜湊了.

# 建立物件的真正步驟:
# ⾸先, 在執⾏類名()的時候. 系統會⾃動先執⾏__new__()來開闢記憶體. 此時新開闢出來的內
# 存區域是空的. 緊隨其後, 系統⾃動調⽤__init__()來完成物件的初始化⼯作. 按照時間軸來算.
# 1. 載入類
# 2. 開闢記憶體(__new__)
# 3. 初始化(__init__)
# 4. 使⽤物件⼲xxxxxxxxx
#
# 類似的操作還有很多很多. 我們不需要完全刻意的去把所有的特殊成員全都記住. 實戰中也
# ⽤不到那麼多. ⽤到了查就是了.

# 總結:
# __new__: 是真正的構造方法(構造記憶體空間再有__init__)
# __init__: 是初始化方法
# 依賴關係:
# 在方法中給方法傳遞一個物件. 此時類與類之間的關係是最輕的
# 關聯關係(組合, 聚合):
# 一對多. 一的一方埋集合
# 多的一方埋實體