一.類與類之間的依賴關係python
大千世界, 萬物之間皆有規則和規律,咱們的類和對象是對大千世界中的全部事物進行歸類,那事物之間存在着相對應的關係,類與類之間也一樣如此,在面向對象的世界中. 類與類中存在如下關係:編程
1. 依賴關係app
2. 關聯關係編程語言
3. 組合關係學習
4. 聚合關係設計
5. 繼承關係code
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 Elphant: def __init__(self, name): self.name = name def open(self, ref): print("大象要開門了. 默唸三聲. 開!") # 由外界傳遞進來一個冰箱, 讓冰箱開門, 這時大象不用揹着冰箱處處跑. # 類與類之間的關係也就不那麼的緊密了, 換句話說, 只要是有open_door()方法的對象. 均可以接收運行 ref.open_door() def close(self, ref): print("大象要關門了. 默唸三聲. 關!") pass def take(self): print("鑽進去") class Refrigerator: def open_door(self): print("冰箱門被打開了") def close_door(self): print("冰箱門被關上了") # 造冰箱 r = Refrigerator() # 造大象 el = Elphant("神奇的大象") el.open(r) # 注意,此時是把一個冰箱做爲參數傳遞進去了,也就是說,大象能夠指定任何一個冰箱. el.take() el.close(r)
此時咱們說, 大象和冰箱之間就是依賴關係,我用着你,可是你不屬於我, 這種關係是最弱的.好比,公司和僱員之間,對於正式員工, 確定要簽定勞動合同, 還得當心伺候着,可是若是是兼職,那無所謂,須要了你就來,不須要你就能夠拜拜了. 這裏的兼職(臨時工) 就屬於依賴關係,我用你可是你不屬於我.
二.關聯關係.組合關係.聚合關係
其實這三個在代碼上寫法是同樣的. 可是, 從含義上是不同的.
關聯關係: 兩種事物必須是互相關聯的,可是在某些特殊狀況下是能夠更改和更換的
聚合關係: 屬於關聯關係中的一種特例,側重點是xxx和xxx聚合成xxx. 各自有各自的聲明週期, 好比電腦,電腦裏有CPU, 硬盤, 內存等等,電腦掛了, CPU仍是好的,仍是完整的個體
組合關係: 屬於關聯關係中的一種特例, 寫法上差很少,組合關係比聚合還要緊密,好比人的大腦, 心臟, 各個器官. 這些器官組合成一我的. 這時人若是掛了,其餘的東西也跟着掛了.
首先咱們看關聯關係: 這個最簡單,也是最經常使用的一種關係. 好比,你們都有男女友,男人關聯着女友,女人關聯着男友. 這種關係能夠是互相的, 也能夠是單方面的.
#Python學習交流羣:778463939 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 at0x103491550>: 456}
雖然顯示的有點兒詭異,可是是能夠用的.
接下來,咱們來繼續研究繼承上的相關內容. 在本節中主要研究一下self,記住,無論方法之間如何進行調用, 類與類之間是何關係, 默認的self都是訪問這個方法的對象.
#Python學習交流羣:778463939 class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) class Foo(Base): pass obj = Foo(123) obj.func1() # 123 運行的是Base中的func1
繼續:
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) class Foo(Base): def func1(self): print("Foo. func1", self.num) obj = Foo(123) obj.func1() # Foo. func1 123 運行的是Foo中的func1
再來:
class Base: def __init__(self, num): self.num = num def func1(self): print(self.num) self.func2() def func2(self): print("Base.func2") class Foo(Base): def func2(self): print("Foo.func2") obj = Foo(123) obj.func1() # 123 Foo.func2 func1是Base中的 func2是子類中的
總結: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.func2() # 111 1 | 111 2 | 222 3
再來,還不夠繞.
#Python學習交流羣:778463939 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() # 拿筆來吧. 好好算
結論: self就是你訪問方法的那個對象,先找本身, 而後在找父類的
四.類中的特殊成員
什麼是特殊成員呢? __init_()
就是一 個特殊的成員,說白了,帶雙下劃線的那一坨,這些方法在特殊的場景的時候會被自動的執行. 好比,
類名() 會自動執行__init__()
對象() 會自動執行__call__()
對象[key] 會自動執行__getitem__()
對象[key] = value 會自動執行__setitem__()
del 對象[key] 會自動執行 __delitem__()
對象+對象 會自動執行 __add__()
with 對象 as 變量 會自動執行__enter__
和__exit__
打印對象的時候 會自動執行 __str__
幹掉可哈希 __hash__ == None
對象就不可哈希了.
abs(對象) 會自動執行__abs__()
bool(對象)會自動執行__bool__()
bytes(對象)會自動執行__bytes__()
float(對象)會自動執行__float__()
int(對象)會自動執行__int__()
對象.index()會自動執行__index__()
len(對象)會自動執行__len__()
next() 會自動執行__next__()
repr()會自動執行__repr__()
round(對象)會自動執行__round__()
copy.對象會自動執行__copy__()
建立對象的真正步驟:
首先, 在執行類名()的時候,系統會自動先執行__new__()
來開闢內存. 此時新開闢出來的內存區域是空的, 緊隨其後, 系統自動調用__init__()
來完成對象的初始化工做,按照時間軸來算.
加載類
開闢內存(__new__
)
初始化(__init__)
使用對象幹xxxxxxxxx
相似的操做還有不少不少,咱們不須要徹底刻意的去把全部的特殊成員全都記住,實戰中也用不到那麼多, 用到了查就是了.