YO~~ 剛跨入AI人工智慧領域的小小工程師, 熱愛自學, 熱愛分享, 下班後的我想為自己Coding, 積極撰寫教學文, 想將自學的程式知識分享給大家, 不斷追求進步的自己, 希望有一天能回饋社會,幫助需要幫助的人, 如果您有什麼很酷的想法,也覺得我還行,歡迎您找我合作~~ IG: https://www.instagram.com/coding_4_me/
給自己的Python小筆記: 物件導向設計OOP教學
哈囉,今天來跟大家介紹一下物件導向設計OOP,相信大家學程式就算沒用到,也都一定會聽到OOP這個概念,在學習程式的過程中,你可能會覺得物件導向這個名詞有聽過,也知道它有三大特性,但好像不一定要用到,我們今天就來一起看看物件導向設計是做什麼的,用了可以幹麻
1. 物件導向設計 與 程序導向設計 差異
a. 程序導向設計: 簡單來說,以函式當程式的基本單元,就是在撰寫專案程式的過程中,我只使用函式(function(def))來寫下我的功能,並用排序的方式來讓程式知道依序跑哪個function,然後通過將比較大的函式切割成多個小函式,來降低程式維護的複雜度。b. 物件導向設計: 簡單來說,以物件當成式的基本單元,就是在撰寫專案程式的過程中,我使用了Class類來創立各種物件,並透過物件間互相傳遞與接收訊息,達成專案的目的。
2. 為什麼要使用物件導向設計:
啊我程序導向設計寫得好好的,幹嘛要會物件導向設計
a. 更容易閱讀: 每個類(Class)都清楚定義了功能 ,讓使用者可以輕鬆閱讀與理解程式邏輯b. 更好維護與新功能添加: 維護上可以清楚針對需要的類(Class)或物件進行修改,也更好擴充新的功能到指定的類(Class)
3. 物件導向 三大特性: 繼承(inheritance)、封裝(encapsulation)、多型(polymorphism)
a.繼承(inheritance) : 簡單來說就是子類別(subclass)繼承一個父類別(class),小朋友繼承了父親有的特性,除非屬性被隱藏起來,設定為private,不然都會被繼承,也就是public屬性都會被繼承
b.封裝(encapsulation): 簡單來說,封裝其實就是將程式包成一個一個的類(class)和函式(function),使用者不需要注意裡面的細節,只要會使用接口就好,像是類.函式名稱()
c.多型(polymorphism): 簡單來說就是大家都繼承了相同的類別,也呼叫相同的函式,但結果卻不同
4. Class 繼承(inheritance)
簡單來說就是子類別(subclass)繼承一個父類別(class),小朋友繼承了父親有的特性,除非屬性被隱藏起來,設定為private,不然都會被繼承,也就是public屬性都會被繼承
a. 繼承的使用方法:
Class(類別)名稱後面的()中,寫下父類別的類別名稱,下面的程式舉例幾種繼承的方法,每個方法中都實作出子類別可以繼承父類別的公開的屬性(實體與類別屬性),也可以自己新增(覆寫)一些屬於子類別才有的屬性
i.第一種方法: 使用Dad_Ken.__init__(self)來繼承,(優點)明確知道指向哪個父類別, (缺點)會有一個麻煩的地方只要繼承的類別改變,就要更動
ii .第二與第三種方法: 使用super(Child_Jen, self).__init__() 或 super().__init__(),他們都改善了第一種方法的缺點,使用這兩種方法還有一個重要原因就是Dependency Injection(依賴注入),那是什麼?簡單來說,就是物件在create時會產生自己需要的dependency, 而依賴注入,就是需要的dependency由client端注入。
iii.檢查繼承關係的方法: issubclass(子類別,父類別),issubclass(Child_Jen, Dad_Ken),如果是的話就會返回True
iiii. 私有屬性: 原則上父類別的私有屬性不會被繼承,除非父類別有設定其他公開的方式取得私有屬性,舉例:__child透過child()獲得
## 父類別 class Dad_Ken: first_name = ‘Hsu’ ## 私有屬性 __child = 1 def __init__(self): self.address = ‘any Town any Street’ self.blood = ‘o’ self.phone_number = ‘0931xx’ ## 私有屬性 Dad_Ken.__child+=1 @property def cook(self): return “I can cook” ## 私有屬性取得方式 @classmethod def child(cls): return cls.__child ## 子類別 繼承父類別 ## 第一種方法 class Child_Jen(Dad_Ken): def __init__(self): Dad_Ken.__init__(self) @property def swim(self): return “I can swim, but my father can’t” ## 第一種方法 Jen = Child_Jen() print(Jen.first_name) # Hsu print(Jen.address) #any Town any Street print(Jen.blood) #o print(Jen.cook) #I can cook print(Jen.swim) #I can swim, but my father can’t print(Jen.child()) #2 ##私有屬性取得 Ken = Dad_Ken() # print(Ken.swim) # AttributeError: ‘Dad_Ken’ object has no attribute ‘swim’ print(Ken.child()) #3 ##私有屬性取得 ## 繼承檢查 print(issubclass(Dad_Ken, Child_Jen)) ## False print(issubclass(Child_Jen, Dad_Ken))## True ##第二種方法 class Child_Una(Dad_Ken): def __init__(self): super(Child_Una, self).__init__() @property def basketball(self): return “I love to plaay basketball” Una = Child_Una() print(Una.first_name) #Hsu print(Una.basketball) # I love to plaay basketball print(Una.cook) # I can cook print(Una.child()) #4 ## 第三種方法 class Child_Jack(Dad_Ken): def __init__(self): super().__init__() @property def run(): return “I can run fast” Jack = Child_Jack() print(Jack.first_name) #Hsu # print(Jack.basketball) # AttributeError: ‘Child_Jack’ object has no attribute ‘basketball’ print(Jack.cook) #I can cook print(Jack.child()) #5
5. 多重繼承
a.多重繼承使用方法:
i. Class(類別)名稱後面的()中,寫下所有父類別的類別名稱,格式: 子類別(父類別1, 父類別2)、subclass(superclass1,superclass2)
ii. 如果所有的父類別擁有相同的屬性,以最左邊的父類別繼承的為優先
iii.當兩個父類別都有__init__時,只會繼承最左邊父類別的__init__底下屬性,但如果有不同的function名稱,就可以都繼承,像是:
print(Tom.blood) ## AttributeError: ‘Child_Tom’ object has no attribute ‘blood’ 當兩個父類別都有__init__時,只會繼承最左邊父類別的__init__底下屬性 print(Tom.cook) #I can cookprint(Tom.cure) #I can cure myself
舉例:
## 父類別1 class Dad_Ken: first_name = ‘Hsu’ ## 私有屬性 __child = 1 def __init__(self): self.address = ‘any Town any Street’ self.blood = ‘o’ self.phone_number = ‘0931xx’ ## 私有屬性 Dad_Ken.__child+=1 @property def cook(self): return “I can cook” ## 私有屬性取得方式 @classmethod def child(cls): return cls.__child ## 父類別2 class Mon_Linda(): first_name = ‘Zin’ def __init__(self): self.mom = ‘Linda’ @property def cure(self): return “I can cure myself” ## 子類別 class Child_Tom(Mon_Linda,Dad_Ken): def __init__(self): super().__init__() Tom = Child_Tom() print(Tom.first_name) ## Zin 以左邊的父類別為優先繼承 print(Tom.blood) ## AttributeError: ‘Child_Tom’ object has no attribute ‘blood’ 當兩個父類別都有__init__時,只會繼承最左邊父類別的__init__底下屬性 print(Tom.mom) #Linda print(Tom.cook) #I can cook print(Tom.cure) #I can cure myself
6. 多型(polymorphism)
簡單來說就是大家都繼承了相同的類別,也呼叫相同的函式,但結果卻不同
舉例: 父類別(Dad_Ken)有個屬性cook, 兩個子類別(Tonny and Tim)都繼承了這個屬性,但呼叫屬性後,產生的結果不同,說明了Python會根據指定的Class(類別),來決定如何實作方法
## 父類別 class Dad_Ken: def __init__(self): self.name = ‘Dad Ken’ def __str__(self): return str(self.name) def cook(self): print(‘Cook by ‘ + self.__str__() ) ## 子類別 1 class Child_Tonny(Dad_Ken): def __init__(self): super().__init__() self.name = ‘Tonny’ def __str__(self): return str(self.name) ## 子類別 2 class Child_Tim(Dad_Ken): def __init__(self): super().__init__() self.name = ‘Tim’ def __str__(self): return str(self.name) print(Dad_Ken().cook()) # Cook by Dad Ken print(Child_Tonny().cook()) # Cook by Tonny print(Child_Tim().cook()) #Cook by Tim
7.封裝
簡單來說,封裝其實就是將程式包成一個一個的類(class)和函式(function),使用者不需要注意裡面的細節,只要會使用接口就好,像是類.函式名稱()
1. Public: 使用者只要知道類裡面有什麼函式可以使用,即可輕鬆使用,不需要知道太多程式過程細節
2. Private: 有些屬性不想讓外界的人直接閱讀的屬性 a. 目的: 很簡單,就是過往我們在Class裡面的屬性都是門戶洞開的,任何人都能輕易看到裡面的內容,但是我們有時候想要一點隱私(private),就是不想被別人輕鬆看見,所以我們要用封裝的方法,將屬性隱藏起來,但我們自己要讀,所以我們要用別的方式讀取這些屬性內容 b. 怎麼做: 我們只要將想要隱藏的屬性是別字加上__(兩個底線)就能輕鬆實現
class House: def __init__(self, address, name, phone_number): self.__address = address self.__name = name self.phone_number = phone_number self.member = 0 little_turtle_home = House(‘any Town any Street’, ‘Turtle’, ‘09xx’) print(little_turtle_home.phone_number) ## 沒封裝成私有: 09xx print(little_turtle_home.__address) ## 有封裝成私有: AttributeError: ‘House’ object has no attribute ‘address’
希望這次也對大家有很多的幫助!!
Reference:
https://medium.com/@zxuanhong/dependency-injection是什麼-ae83f7f87d6d
https://codertw.com/程式語言/115956/
https://medium.com/tsungs-blog/python-初探物件導向-59c97981c7d6
喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。
发布评论…