--- lang: zh-tw tags: Python title: 類別與物件(入門版) - Python 教學 description: 中興大學資訊研究社1101學期程式分享會主題社課 image: none --- ###### [Python 教學/](https://hackmd.io/7-LP9CyOThOdkEbq44FLvw) # 類別與物件(入門版) > [name=Hui][time= 110,12,9] > 根據我朋友的意見,這邊可能會有點難以理解 如果觀看時有任何不適,包含噁心、頭暈目眩、無法理解,請立即舉手反映 另外,有些地方可能會有一點點的不精準,那是為了方便各位理解還請見諒 ## 物件導向觀念 Python是一種物件導向的程式語言。在Python中,幾乎所有的東西都是一個物件(object)。 包含function本身也是 ```python= def foo(): print(hellow) print(type(foo)) #印出foo 是甚麼東西 print(dir(foo)) #印出foo 裡有甚麼東西 ``` output ``` <class 'function'> ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] ``` 一個物件最主要的組成即是**屬性(Attribute)**和**方法(Method)** >另外你看到所有有兩個底線的東西都是預設值,初學不用理會即可 #### 練習1 請印出**list**中的所有成員(Attributes and Methods),並觀察之 >hint: use dir() ### 類別(class) 類別(class)就像構建物件的「藍圖」,或者說是一個構建物件的函式。 另外,物件中的方法(Method)是指在物件裡的函式,物件中的屬性( Attributes)是指物件裡的變數。 >Method: 舉個例來說,我們常用的list.append() 就是list的Method >Attributes: 物件裡的變數 ### 實例(instance) 如果類別是藍圖的話,那instance就是實體啦,也就是object本身。同一個class 的不同instance是彼此獨立的(當然也有方法讓他們共享某些資料) 而在python 中可以使用函式"isinstance"來檢查是否為該class的實例 >isinstance(obj,class) # True if object is the instance of the class else False 如 ```python= l = [1,2,3] print(isinstance(l,list)) #>>> True ``` ```python= dic = {'a':'apple','b':'ball'} print(isinstance(dic,dict)) #>>> True ``` ### 名稱 名稱與別名的問題我們在使用list常常遇到,如下面範例 ```python= a=[1,2,3] b=a a.append(4) print(a) #>>> [1, 2, 3, 4] print(b) #>>> [1, 2, 3, 4] print(a is b) #>>> True ``` 我們可以得知a 實際上跟b是同一個東西 >使用"is"來檢查是否為同一個物件 詳見:https://docs.python.org/zh-tw/3/tutorial/classes.html#a-word-about-names-and-objects #### 練習2 ```python= a = [1,2,3,4] b = [1,2,3,4] print(a == b) #Q1 print(a is b) #Q2 ``` 請回答 Q1、Q2分別會印出甚麼? #### 補充 如果想要複製一份list,而不是表示同一份list的話請使用 ```python= a=[1,2,3] b = a[:] #用法1 c = a.copy() #用法2 print(a,b,c) #>>> [1,2,3][1,2,3][1,2,3] a.append(4) print(a,b,c) #>>> [1,2,3,4][1,2,3][1,2,3] ``` # 實際練習 還記得上次教的函式庫嗎? 這次我們用 datetime 作為範例來講解以下行為 說明文件:https://docs.python.org/zh-tw/3/library/datetime.html ```python= import datetime ``` 我們先來看看這個模組都提供了些甚麼東西吧 ```python= help(datetime) ``` 節錄 ``` ... CLASSES builtins.object date datetime time timedelta tzinfo timezone ... ``` 或者你可以點開上面網址 找到 ![](https://i.imgur.com/qxBdeWJ.png) 這些都是這個模組提供的類別(class) ## 建立(初始化) **我們以datetime中的date為例** ### 建構子 按圖施工 我們要建立一個class的instance,必須按照class規定的方法。 另外這個建立instance的"方法",我們稱之為建構子,他的呼叫方式就是class自身的名子 >就有點像你要用原料去製造一個東西一樣,那建構子就是製造這個東西的方法 找到說明文件的下面對於date物說明的地方 ![](https://i.imgur.com/UATRkDx.png) 這是最基礎的建構方法,之後其他的建構方法都是基於此方法延伸出來的 我們觀察一下 >class datetime.date(year, month, day) > 在上列程式碼的描述中date後面直接放參數,表示他是建構子,需要建立date物件時直接呼叫即可 ![](https://i.imgur.com/mboUcbk.png) 試試看下列程式碼 ```python= import datetime this_day = datetime.date(2021,12,9) print(this_day) ``` #### 練習3 建立一個 **2022年11月16日** 的 **date** 物件 ### 延伸方法 而在此基礎上,通常一個class也會提供建立特定物件的方法,例如**date**這個類別提供了[這些](https://docs.python.org/zh-tw/3/library/datetime.html#date-objects)方法來建立物件。 我們以**today**為例 ```python= import datetime this_day = datetime.date.today() print(this_day) #>>> 2021-12-09 ``` #### 練習4 使用"2022-11-16"來建立**date**物件 >hint: 去剛剛[那個](https://docs.python.org/zh-tw/3/library/datetime.html#date-objects)網頁找找看有沒有支援的方法 ## 屬性(Attribute) **date** 裡面提供了三個屬性(不包含預設的) ![](https://i.imgur.com/BigJezf.png) 看到有藍色磚塊的那ㄍ,那個就是了 ```python= import datetime this_day = datetime.date.today() print(this_day.year) #>>> 2021 print(this_day.month) #>>> 12 print(this_day.day) #>>> 9 ``` ### 練習5 承練習4,請印出該物件的日期 >2022年11月16日 ### 練習6 計算生命靈數計算機 >生命靈數怎麼算? 將你的西元出生年月日全部數字加總,如果得出的是二位數,此兩數再相加,直到成為個位數字,即可得到你的生命靈數,也可以知道你是屬於幾號人(共1-9號人)。 2+2=『4』→此為你的生命靈數哦! >如 2000年 11月 11日則為 2+0+0+0+1+1+1+1 = 6 >-by google 給定一個datetime.date物件,請補全下列function以回傳生命靈數 ```python= import datetime def magicLifeNumber(birthday: datetime.date) -> int: # to do ..... ``` >hint1: 請注意datetime.date 中各屬性的型別 >hint2: >使用下方程式碼以檢查你的答案是否正確(會印出5) >test_birthday = datetime.date(1999,11,29) print(magicLifeNumber(test_birthday)) ::: spoiler **Answer** ```python= def magicLifeNumber(birthday: datetime.date) -> int: birthday_string = str(birthday.year) + str(birthday.month) + str(birthday.day) while (len(birthday_string) >= 2): temp = 0 for c in birthday_string: temp += int(c) birthday_string = str(temp) return temp ``` ::: ## 方法(Method) >這邊我們暫時只探討實例方法(instance method) 物件的方法為物件的function,是可呼叫的 並且是物件提供我們對物件的操作手段,或是藉由物件的屬性延伸的以資料(例如剛剛的生命靈數函示) 例如list.append()就是list提供的方法 下面我們將繼續以datime.date作為例子 一樣我們看到[這邊](https://docs.python.org/zh-tw/3/library/datetime.html#date-objects) 根據這段描述 ![](https://i.imgur.com/FUH3rIV.png) ```python= import datetime this_day = datetime.date.today() print(this_day) #>>> 2021-12-9 another_day = this_day.replace(year=2022) print(another_day) #>>> 2022-12-9 ``` another_day 則為一個新的datetime.date物件,並擁有屬性 year=2022,month=12,day=9 還有一些有趣的,例如 ```python= import datetime this_day = datetime.date.today() print(this_day.isoweekday())# 今天禮拜4 ``` #### 練習7 查看datetime.date的說明 找到方法使用上面的**this_day**印出 >Thu Dec 9 00:00:00 2021 >hint 方法是需要透過呼叫的,記得加小括號 ## 繼承 以剛剛datetime.date 為例,我們在表示日期時常常也會需要表示時間 那怎麼辦呢? 難不成只有日期時使用這份code,加上時間的話我們要再寫另一份code? 這時候我們就會用到繼承啦! 在**datetime**這個模組中,還有另一個class叫**datetime**(datetime.datetime) ```python= import datetime this_day = datetime.datetime.now() print(this_day) #>>> 2021-12-09 09:47:22.154680 ``` 他在日期的基礎上又多加上了時間的功能,換而言之 **datetime.date**繼承了**datetime.datetime** datetime.datetime 為父類別 datetime.date 為子類別 ### 特性 繼承的特性是父類別的所有成員(屬性與方法),子類別通通都要有,而且名稱必須一樣 當某個功能需要使用父類別時,那完全可以使用子類別來代替 例如: ![](https://www.9x9.tw/public/files/product/b2101920300260.jpg) 繼承 ![](https://i.imgur.com/bzKNiPS.jpg) 當有人需要紅筆時,你完全可以拿上面那支筆給他 #### 練習8 複製練習6的答案,並傳入一個datetime.datetime的物件進去,觀察程式的情況 ## 補充 ### 反射(reflex) reflex 顧名思義是要先照到物體才會有反光 在程式語言中,我們會用於檢查物件 如dir(), type() 等等,希望由物件來自己告訴我們她的特徵 ### 預設屬性 python 中的所有物件都是繼承baseobject中而來,所以有些屬性是已經存在的,在命名上,一般會在前後各家兩個底線 (\_\_xx\_\_) 使用dir()看到的就是這些 並且同時是readonly ### print 其實我們在使用print(obj)時,就是在調用obj.\_\_str\_\_(),由它的回傳字串來決定螢幕上印的東西 當你需要該物支援該物件在螢幕上的列印時修改她即可 ```python= class hyper_datetime(datetime.datetime): def __str__(self): return self.ctime() a_day = hyper_datetime.now() print(a_day) ```