# Python物件導向,淺談class ###### tags: `人生苦短,我學Python` ## 物件導向概述 :::success :sign_of_the_horns: 物件導向程式設計(Object Oriented Programming)簡稱OOP,主要針對大型軟體設計而提出,它可以使軟體設計更加靈活。 ::: ## 對象 :::warning 這是一個抽象的概念,世間萬物皆為對象。比如一個人。 ::: * 靜態被分為屬性,任何對象都具備自身屬性,如人的性別 * 動態表示對方的行為,及對象執行的動作,孺人可以行走 * 在Python中,一切都是對象。 ## 類 :::danger 類是封裝對象的屬性及行為的載體,反過來說,具有相同屬性和行為的類實體被稱為類 ::: ## OOP設計特點 :::success 1. 封裝 將對象的屬性和行為封裝起來,而將對象的屬性和行為封裝起來的截體就是類,類通常對客戶隱藏實際細節。 2. 繼承 子能繼承父的特性,但無法反過來 3. 多態 一個父親能有多個兒子,兒子能繼承父親的技能,但兒子們也有自身的技能 ::: ## 定義類 * 在Python中,類的定義使用class關鍵字 ```python= class Classname: statement ``` * 也可以先用pass卡著 ```python= class Geese: pass ``` ## 創建類的實例 ```python= classname(parameterlist) ``` * 比如,定義一個Geese類的實例 ```python= wildGeese = Geese() print(wildGeese) # <__main__.Geese object at 0x000002AD716B4DC0> ``` ## 建立__init__方法 :::warning :warning: __init__是一個特殊的方法,每當創建一個新實例的時候,Pytho都會自動執行它。 :warning: __init__方法必須包含一個self參數,而且必須是第一個參數。 :warning: self參數是指象實例本身的引用,屬於訪問類的屬性和方法。 :warning: 在方法要調用時會傳遞實際self參數。 :warning: 因此,當__init__方法只有一個參數時,就不需要只掉參數。 ::: * 舉例 ```python= class Geese: def __init__(self): print("我是大雁類") wildGeese = Geese() # 我是大雁類 # 如果把self拿掉便會出現...... # TypeError: __init__() takes 0 positional arguments but 1 was given # 所以說還是需要self的 ``` * 其實還可以自定義參數 ```python= class Geese: def __init__(self, beak, wing, claw): print("我是大雁類") print(beak) print(wing) print(claw) beak_1 = "嘴" wing_1 = "翅膀" claw_1 = "爪子" wildGeese = Geese(beak_1, wing_1, claw_1) # 我是大雁類 # 嘴 # 翅膀 # 爪子 ``` # 創建類的成員並使用 * 創建實例方法並使用 ```python= def funcName(self, parametetlist): block ``` * 創建方法完成後,可以透過類的實例名稱和"."操作符進行呼叫 ```python= instanceName.functionName(parametervalue) ``` * 實際創造一個函數(fly()) ```python= class Geese: def __init__(self, beak, wing, claw): print("我是大雁類") #print(beak) #print(wing) #print(claw) def fly(self, state): print(state) beak_1 = "嘴" wing_1 = "翅膀" claw_1 = "爪子" wildGeese = Geese(beak_1, wing_1, claw_1) wildGeese.fly("我可以直衝雲霄") # 我是大雁類 # 我可以直衝雲霄 ``` * 創建數據成員並使用 ```python= class Geese: neck = "脖子" def __init__(self): print(self.neck) geese = Geese() # 脖子 # 此寫法等同於 self.neck = "脖子" print(self.neck) ``` ## 訪問限制 :::success :warning: _foo : 以單下滑線開頭表示protect(保護)類型的,只允許子類及本身,不能使from module import * 語句導入。 :warning: __foo():雙下滑線到表私有,只允許定義該方法的類本身進行訪問,可以透過"類的實例名.類名.__xxx"方式訪問。 :warning: __foo__():代表特殊定義方法,一般表示系統定義名字,比如:__init__() ::: ## 屬性 * 建立用於計算的屬性 ```python= @property def methodname(self): block ``` * 實際運用 ```python= class Reat: def __init__(self, width, height): self.width = width self.height = height @property def area(self): return self.width * self.height print(Reat(100, 200).area) # 2000 ``` :::info :page_with_curl: 轉化成屬性後,就可以直接透過方法名來訪問方法,就不需要添加小括號 ::: * 添加安全保護機制 ```python= # 想要建立可以讀取但不能相改的屬性可以用@property實踐 class TVshow: def __init__(self, show) : self.__show = show @property def show(self): return self.__show tsShow = TVshow("正在播放<<8964>>") print("默認: ", tsShow.show) # 默認: 正在播放<<8964>> # 那如果改成... # tsShow = "正在播放<<爆打粉紅>>" 修改屬性值 # print("修改後: ", tsShow.show) 獲取屬性值 # AttributeError: 'str' object has no attribute 'show' ``` ## 繼承 * 簡單明瞭,就是繼承父類 ```python= class className(baseclasslist): Statement ``` * 比如說.... ```python= class fruit: color = "green" def fruitcolor(self, color): print("水果顏色是: ", color) print("-----------") print("原本的顏色是: ", fruit.color) class Apple(fruit): color = "red" def __init__(self): print("我是蘋果") Apple().fruitcolor(Apple.color) # 我是蘋果 # 水果顏色是: red # ----------- # 原本的顏色是: green ``` ## 方法重寫 :::success :heavy_check_mark: 在自身認為不適用的情況下,對def內部的函式內容作改寫。 ::: ## 使用super()呼叫父類 :::success :brain: 如果要在子類中引用父類的方法,但是又需要新增一些子類所特有的內容,可通過類名.方法()和super()來呼叫父類的方法,再個性化子類的對應函式。 :scream: 直接使用類名.方法()來呼叫時,還是需要傳入self為第一個引數,而使用super()呼叫則python自動將self傳入,因此使用super()比較簡潔。 :mega: 好處 :bug: 簡化程式碼 :bug: 如果父類名稱修改,對其他呼叫父類函式的類來說也沒有影響,而如果直接使用父類的名稱來呼叫,父類名稱修改會影響其他所有的類。 ::: * 舉例 ```python= class drive: def __init__(self, name): self.name = name def getname(self): return self.name def displayVehicle(self): print("廠牌: ", self.name) class car(drive): def __init__(self, name, mod): super().__init__(name) # 呼叫父類建構函式 self.mod = mod def display(self): print(self.getname()) print(self.mod) drive("BMV").displayVehicle() car("totya", "GH333").display() # 廠牌: BMV # totya # GH333 ``` {%hackmd S1DMFioCO %}