# Python 3 語法大全 <br>目錄 (點擊可以跳轉) * <a href=#variable>變數及型態轉換</a> * <a href=#operator>運算子</a> * <a href=#inout>輸入輸出</a> * <a href=#if>條件判斷式(if)</a> * <a href=#loop>迴圈(Loop)</a> * <a href=#container>容器</a> * <a href=#string>字串處理</a> * <a href=#function>函數</a> * <a href=#mod>模組</a> * <a href=#file>檔案處理(IO)</a> * <a href=#exception>例外處理</a> * <a href=#class>類別(class)</a> ## <p id = "variable">變數及型態轉換</p> 在Python每個東西都是物件(Object) <br> ### 變數 **宣告變數方法:** <br>**變數名稱 = 值**<br> <br>名稱限制: * 第一個字母必須是英文或_(底線)或中文(不建議) * 剩下只能是英文、中文(不建議)、_(底線)或是數字,不可以使用其他符號 * 不能為關鍵字,如果使用了可能會造成,原來的關鍵字無法正常使用 <br>宣告一個整數 ``` x=100 ``` <br>宣告一個布林值(bool,真假值) ``` y=True ``` <br>宣告一個字串(String) ``` a="I am string1" b='I am string2' ``` 使用**del**可以刪除變數,讓其從記憶體消失 ``` a=42 del a ``` ### 型態轉換 可以將變數或資料轉換為你需要的型態,前提是要可以轉換 使用type()可以得知變數的型態 舉例: * int() 將物件轉成int型態 * str() 將物件轉成string型態 * list() 將物件轉乘list容器型態 範例 ``` a=10 b='95' c=(4,2,3,8,9) print(type(a),type(b),type(c),sep='\n') a=str(a) b=int(b) c=list(c) print(type(a),type(b),type(c),sep='\n') ``` 輸出結果: ``` <class 'int'> <class 'str'> <class 'tuple'> <class 'str'> <class 'int'> <class 'list'> ``` ### 全域變數vs區域變數 一般我們宣告使用的變數為全域,而像是函式的參數或是函數內部宣告的變數就是區域變數 兩者的差別 區域變數:當離開宣告所在的區塊,會從記憶體中釋放,因此不能在區塊外使用,所以不同區域內部的變數可以名稱相同 全域變數:一直存在直到全部程式跑完 當在區域(例如函數裡面)內,有區域變數和全域變數同樣名稱時,會優先使用區域變數。 --- ## <p id="operator">運算子</p> 運算要先有運算式 ### <br>運算符號 * **+** &nbsp;&nbsp;加號 * **-** &nbsp;&nbsp;&nbsp;減號 * **/** &nbsp;&nbsp;&nbsp;除法 * **//** &nbsp;整數除法只取商,餘數捨去 * **%** &nbsp;除法,取餘數 * <b>*</b> &nbsp;&nbsp;乘法 * <b>**</b> 指數 ``` a=4**5 #a=1024 b=a+6 #b=1030 ``` ### 複合指派運算子 形式: 變數(任一運算子)=值 即為 變數=變數 運算子 值 ``` a=10 a/=5 #a=a/5 a=2 ``` ### <br>關係運算子 關係運算子用於判別真假值後回傳真假值(bool),通常用於條件判斷,例如if或while<br> 關係運算子符號 * **==** 相等 * **!=** &nbsp;不相等 * **>** &nbsp;&nbsp;大於 * **>=** 大於或等於 * **<** &nbsp;&nbsp;小於 * **<=** 小於或等於 * **is** &nbsp;&nbsp;兩個東西是否為本質一樣,或是說是否共用同一塊記憶體 * **and** 可以用來串聯兩個判斷式,當兩個判斷式為True,回傳True * **or** 可以用來並聯兩個判斷式,當兩個判斷式至少一個為True,回傳True * **not** 當判斷式為False,就回傳True ``` 5>10 #False 8<=10 #True a=10 b=a a is b #True ``` ### 補充內容 問題一: 當兩個整數(a和b)本質一樣後,為什麼b改變不會影響a? ``` a=10 b=a a is b #True b=100 #b=100 a=10 ``` 原因: Python不像c語言(靜態語言)一樣。 事實上,a變數指向的是為10的物件,所以當一開始b=a,代表b也指向了這個相同物件,因此本質上相同,然而將b=100,就是使b指向了另一個為100的物件,因此a不會隨b而改變。 <br> 問題二: 當兩個整數令為相同值,為什麼會本質一樣(指向相同記憶體位置)? ``` a=50 b=50 a is b #True ``` 原因: Python的資料物件,有分為兩種,而整數是屬於不可變的資料型別,下面將介紹Python的資料型別 ### Python的資料型別 1. 可變的資料型別(ex:List,Dict) 可變即代表對同一物件值是可變的,因此當值改變,變數依舊指向同一物件 2. 不可變的資料型別(ex:Int整數,float浮點數,String字串,Tuple) 不可變即代表對同一物件值是不可變的,因此當值改變,變數必須指向到新創建的物件,且每個物件的值不會重複,當物件沒被指向,即會收回記憶體,所以**問題二**的原因就是因為,整數為不可變的資料型別,因此當都令為同一個值的時候,會指向同個物件,此外也能節省記憶體空間。 <br> --- ## <p id=inout>輸入輸出</p> ### 輸入 **input('請輸入資料:')** 括號內可放字串作為說明文字,此外輸入後的型態必為String **eval():將字串變成數字** 可以把字串轉成數字(整數或小數),若字串不為完全的數字無法轉換並error 此外還可以執行使用者輸入的指令 範例 ``` a=input("請輸入指令:\n") eval(a) ``` 輸入 ``` print('hello world!') ``` 輸出結果 ``` hello world! ``` **str():將數字變成字串** 可以把數字轉成字串 ### 一般輸出(print) print(value,sep=' ',end='\n',file=sys.stdout,flush=False) 這些參數都能自己設定 **value**可以放多個並用,隔開 **sep**預設為半形空白,當輸出很多不同資料時,中間會輸出的字串,用於隔開不同值 **end**預設為一個換行(\n),當輸出完所有值後,要作為結尾的字串 **file**預設為sys.stdout(螢幕),用於設定輸出裝置 **flush**預設為False,決定是否在執行完print後,立刻輸出,而不是放在緩衝區,等同一區塊程式都輸出後,才一起輸出,在迴圈時會需要注意。 **範例** ``` print('Hello','world',sep='\n',end='!!!') ``` 輸出 ``` Hello world!!! ``` ### 格式化輸出(print) 如果面對,字串與變數交錯的印,可以更方便的輸出,使用方法為在要印出的字串裡面要印變數的地方加上格式詞,然後在字串後加上%(),括號內放入變數,若多個照順序並用逗點隔開 此外sep和end都可以搭配使用 **格式詞** 根據變數類型選擇對應格式,否則可能會出錯 * **%d** 以十進位整數方式輸出 * **%f** 以十進位浮點數方式輸出,**%.Xf** X可以為0~6,即可以決定印到小數點後幾位,然後四捨五入 * **%%** 在字串中顯示%的方法,否則只打一個會被認為是格式詞沒正確輸入 * **%s** 以字串(str())輸出,變數只要能用str()傳換就能印,**%.Xs**X的大小代表字串要從頭印幾個字元出來 * **%e,%E** 將浮點數以科學記號輸出 * **%o** 以八進位整數方法輸出 * **%x,%X** 以十六進整數方式輸出 * **%c** 以字元方式輸出 * **%r** 以字串(repr())輸出,變數只要能用repr()轉換就能印,在某些時候會跟用%s輸出結果不同,例如在同樣輸出字串時,%r會再該字串左右加上上下引號 **對齊技巧** **Y+格式詞** 格式詞可為任何 Y為一個數字,Y>0為靠右對齊,Y<0為靠左對齊,Y及代表最少的半形空格數,若印的內容超出則不理會,若沒超出且Y為正數則會補空格在輸出的左邊,反之為補空格在右邊,所以若想完全對齊要確保Y大於等於最大的可能輸出長度 此外在Y>0的時候,Y左邊加上0可以使空白部分全補成0 另一種方法(用米字號代替): ``` b=10 print('%*d'%(b,a))等於print('%10d'%(a)) ``` 範例: ``` a=30 string1='apple' b=679.42387 print('%5d\n%3o\n%x'%(a,a,a),end='\n\n') print('str():%s\nrepr():%r'%(string1,string1),end='\n\n') print('%1.3f\n%10.4f\n%10.1f'%(b,b,b)) print('%-10d'%a,'%-10.3s'%string1,sep='<---\n',end='<---\n') print('%010.1f'%b) ``` 輸出結果: ``` 30 36 1e str():apple repr():'apple' 679.424 679.4239 679.4 30 <--- app <--- 00000679.4 ``` ### 使用dict進行格式化輸出 可以使用當格式輸出的變數,但key值必須為字串 範例 ``` mydict={'a':'apple','ba':42.8664,'s':10} print('%(a)s,%(s)d,%(ba)7.2f'%mydict) print('%(a)s,%(s)d,%(ba)7.2f'%{'a':'apple','ba':42.8664,'s':10}) ``` 輸出結果: ``` apple,10, 42.87 apple,10, 42.87 ``` ## <p id = "if">條件判斷式(if)</p> 使用if可以用來決定程式的執行方向,並達到跳躍執行程式的效果 此外執行的程式碼必須使用4個空白或是一次tab來縮排,所以可以來看縮排得知是否為同一層程式碼,而同一層和同一個if的else只能有一個 ### **單層if**,else部分可以不需要 ``` if 判斷式: 當判斷式為真(True),執行的程式碼 else: 當判斷式為假(False),執行的程式碼 ``` ``` if a>b: print('a大於b') else: print('a小於b') ``` ### **elif用法** ``` if 判斷式1: 當判斷式1為真(True),執行的程式碼 elif 判斷式2: 當判斷式2為真(True),執行的程式碼 else: 當以上判斷式都為假,執行的程式碼 ``` 範例 ``` if 5>10: print('a') elif 5>3: print('b') else: print('c') ``` 輸出 ``` b ``` 若將elif分開.... 範例 ``` if 5>10: print('a') else: print('c') if 5>3: print('b') else: print('c') ``` 輸出 ``` c b ``` ### **多層(巢狀)if** ``` if 10>5: if 10>10: print('a') if 10>8: print('b') else: print('c') ``` --- ## <p id="loop">迴圈(Loop)</p> 迴圈可以重複執行某段程式碼 ### **for迴圈** 通常用在知道迴圈要跑的次數用for迴圈 執行的程式碼也要縮排或是空白4格 宣告一個跑n次的迴圈,i可替換為任何已存在變數 ``` for i in range(n): print(i); ``` 其他宣告方法: 根據給的容器(迭代器)大小跑迴圈(以下範例的容器的大小為4) ``` for i in [5,3,1,2]: print(i) #印出i的值 ``` 輸出結果: ``` 5 3 1 2 ``` **range()** **使用方法一:** range(n) 代表產生一個容器裝有0到n-1,共n個數字 **使用方法二:** range(起始值(預設為0),終止值,每次增加的量),若省略不打增加的量則預設為+1 範例 ``` for i in range(20,10,-2): print(i) ``` 輸出結果: ``` 20 18 16 14 12 ``` ### **while迴圈** 通用於不能保證迴圈要跑幾次時使用 ``` while 判斷式: 判斷式為真時,執行的程式碼 ``` 範例 ``` a=0 while a<=40: a+=10 print(a) ``` 輸出結果: ``` 10 20 30 40 50 ``` **巢狀迴圈** 使用for時,要注意變數,不要重複使用同樣變數(i)來跑,否則會造成迴圈出意外 此外要注意內部圈跑完才會回到外部迴圈 ``` while 判斷式1: 判斷式1為真時,執行的程式碼 While 判斷式2: 判斷式2為真時,執行的程式碼 ``` 範例 ``` for i in range(3): for j in range(i): print('hello') print('next loop~') ``` 輸出結果: ``` next loop~ hello next loop~ hello hello next loop~ ``` <br> **break** 如果想在迴圈還沒跑完前就立即終止它(立即終止代表break後面的待在同層的程式碼也不會被執行),可以使用break,通常可以搭配if使用 此外break只會終止自己待在的那層迴圈,而不會將整著巢狀迴圈都終止 範例 ``` a=0 while(True): if (a>5): break; print(a) a+=1 ``` 輸出結果: ``` 0 1 2 3 4 5 ``` <br>**continue** 如果想跳過一次迴圈內部(跳過continue後面迴圈內部的程式碼)的執行可以使用continue,通常搭配if使用 範例 ``` for i in range(4): if i==2: continue print(i) ``` 輸出結果: ``` 0 1 3 ``` --- ## <p id="container">容器</p> 容器是用來放置東西(可以同時放不同種東西),而每種容器都有著不同特性以及不同方法(透過容器的自訂(變數)名稱加上.加上要呼叫的方法ex:a.add(),此外只要是方法(function)都要加上小括號) ### 容器通用方法(其實有些容器只能使用下列部分方法) **容器名稱[]** 可以取內部的值 **len(容器名稱)** 可以知道內部的長度(大小) **iter(容器名稱)** 會根據容器類型,建立其專屬的迭代器,可以用於要跑完一遍(尋訪)容器內部的for迴圈,若用在dict,則是以key值建立(**若物件是Iterable,可以不用建立迭代器,也可直接尋訪**) **物件 in 容器名稱** 檢查物件是否在容器中,回傳布林值(如果用在dict則是查key值是否存在) **del 容器名稱[index值(key)]** 刪除在那index值的東西,若容器是dict,則刪除對應於key的value值 **迭代器使用範例(好處在於可以不用知道容器大小就可以走遍(尋訪)容器)** ``` a=(3,2) for item in iter(a): #尋訪tuple,iter(a)的部分可以直接換成a print(item,' ',end='') print() b=[4,3,2] for item in iter(b): #尋訪list,iter(b)的部分可以直接換成b print(item,' ',end='') print() c={2,5,'apple'} for item in iter(c): #尋訪set,iter(c)的部分可以直接換成c print(item,' ',end='') print() d={'a':5,6:'i'} for item in iter(d): #尋訪dict,iter(d)的部分可以直接換成d print(item,' ',end='') print() ``` 輸出結果: ``` 3 2 4 3 2 apple 2 5 a 6 ``` **小技巧** (在使用官方IDE)此外當容器被建立可以打上容器的變數名稱加上.並按下tab即能看到所有的可用方法,並使用上下鍵即能自動打上方法,**此方法適用python任何物件** ![](https://i.imgur.com/NN1kq3p.png) 左邊是文字編輯模式(每次需先Run過打上的程式碼,才能正常用tab,否則它無法辨識為正確的物件類別),右邊是Shell <br>**容器比較** ![](https://i.imgur.com/sussjJN.png) **勘誤3.6版(含)之後dict是有順序性的** ### <br>**tuple序對** 特性:有順序性,一旦建立無法修改內部內容 範例(可以使用[0]來回傳第0位的位置的值,使用[1]則就是回傳第1位的位置值,以此類推) ``` t=(4,2,3,'7') print(t[0]) print(t[1]+t[2]) print(t[3]) ``` 輸出結果: ``` 4 5 7 ``` **tuple的方法(function)** **index()** 從頭尋找出現在tuple的值,並回傳第一個出現的index值(位置),**找不到會直接跳錯誤訊息** 使用方法: index(n)代表在容器的最大範圍內找第一個出現n的index值 index(n,a,b)代表在容器的index為a到index為b的範圍(不含b)找第一個出現n的index值 **count()** 回傳值在tuple內出現的次數 使用方法: count(n)代表找n在tuple出現的次數 範例 ``` a=(4,8,1,4,4) print(a.index(1)) print(a.index(1,0,3)) print(a.count(4)) ``` 輸出結果: ``` 2 2 3 ``` ### **list串列** 特性:有順序性,可以增加,刪除,修改內容 範例(也可以使用[]來得知特定位置的值) ``` a=['mouse',4,5,'apple'] print(a[0]) print(a[2]) ``` 輸出結果: ``` mouse 5 ``` **list的方法(function)** **append()** 在list的最後面加上一個資料成員(物件) 使用方法: append(n)代表把n加到list最後面 **extend()** 在list的最後面加上一有順序的物件(容器) 使用方法: extend(n)代表把容器n加到list最後面 **clear()** 將list內清空,只留下殼 使用方法: clear() **insert()** 將資料成員插入指定的index值(位置) 此外,若放的位置 使用方法: insert(i,n)代表將n放到index值為i的位置 注意: **若i為大於現有最大index值**,則會被放到最後面 **若i為負數則代表放到從後面數來i+1的位置,若已經倒數到index為0,則就放到第0位**例如:i=-1則代表放到倒數第二位 **remove()** 從頭開始,找指定的值,找到的第一個,將它移除 使用方法: remove(n)代表,從頭開始找n,找到的第一個將它移除 **pop()** 將指定index值(位置)的值移除,並回傳被刪除的值 使用方法: pop()代表,刪除最後一個位置的值並回傳值 pop(i)代表,刪除index(位置)為i的值並回傳值 **copy()** 將list複製並回傳 使用方法: copy()代表複製list,並回傳複本 **index()** 從頭尋找出現在list的值,並回傳第一個出現的index值(位置),**找不到會直接跳錯誤訊息** 使用方法: index(n)代表在容器的最大範圍內找第一個出現n的index值 index(n,a,b)代表在容器的index為a到index為b的範圍(不含b)找第一個出現n的index值 **count()** 回傳值在list內出現的次數 使用方法: count(n)代表找n在tuple出現的次數 **sort()** 將list排序,數字依大小排序(從小到大),字串依字母前後順序及長度排序 此外,當list內部不是只有一個種類的物件(如有字串和數字同時存在),無法使用排序,只會發生錯誤 使用方法(): sort() **reverse()** 將list順序完全倒過來 使用方法: reverse() 範例 ``` a=[] a.append(40) a.append(20) print(a) b=a.copy() print(b) a.extend(b) print(a) a.clear() print(a) b.insert(-1,54) print(b) b.reverse() print(b) b.remove(54) print(b) c=b.pop() print(b) print(c) ``` 輸出結果: ``` [40, 20] #a [40, 20] #b [40, 20, 40, 20] #a [] #a [40, 54, 20] #b [20, 54, 40] #b [20, 40] #b [20] #b 40 #c ``` ### **set集合** 特性:無序性,可以更改資料,類似數學概念的集合,內部成員資料不能重複 範例 ``` a={5,7,8,8,5,'apple'} print(a) ``` 輸出結果(由於是無序性的,所以每次印出來的結果可能會不同): ``` {8, 'apple', 5, 7} ``` **set的方法(function)** **add()** 將物件加入集合當中 使用方法: add(n)代表將n加入集合當中 **clear()** 將集合清空,只留下殼 使用方法: clear() **copy()** 將集合複製一份,並回傳 使用方法: copy() **pop()** 將集合中隨意一個成員拋棄,並回傳 使用方法: pop() **remove()** 將指定元素從集合中移除,找不到該元素會跳錯誤訊息 使用方法: remove(n)代表將n從集合移出 **discard()** 跟remove()一樣會將指定元素從集合移出,但找不到該元素時不會跳錯誤訊息 **difference(),intersection(),union()** 將原來的集合和另一個集合做(差集/交集/聯集)運算,並把結果回傳為一個新集合 使用方法: difference(myset),intersection(myset),union(myset)代表將使用這個方法的set與myset做(差集/交集/聯集)運算,並將結果回傳 **difference_update(),intersection_update(),update()** 將原來的(呼叫這個方法的)集合和另一個集合做(差集/交集/聯集)運算,並把結果覆蓋到原來的集合 使用方法: difference_update(myset),intersection_update(myset),update(myset)代表將使用這個方法的set與myset做(差集/交集/聯集)運算,並將結果覆蓋到呼叫方法的set **issubset()** 判斷呼叫的集合是否為指定集合的子集合,回傳真假值(bool) 使用方法: issubset(myset)代表判斷呼叫的集合是否為myset的子集合 **isuperset()** 判斷指定的集合是否為呼叫的集合的子集合,回傳真假值(bool) 使用方法: issubset(myset)代表判斷myset是否為呼叫的集合的子集合 範例: ``` a={10} a.add(20) a.add(80) a.add(40) a.add(20) print(a) b=a.copy() print(b) c=b.pop() print(c) print(b) if b.issubset(a): print('TRUE') else: print('False') d={60,20} a.intersection_update(d) print(a) f=b.intersection(d) print(f) ``` 輸出結果:(由於使用了pop(),輸出結果可能會不同) ``` {80, 10, 40, 20} #a {80, 10, 40, 20} #b 80 #c {10, 40, 20} #b TRUE {20} #a {20} #f ``` ### dict字典 特性:無順序性(3.6版開始有順序性),有特別對應關西(一個key對上一個value),key之間不能重複,value則沒此限制,可以更改內容,此外key的型態不能為list或dict(因為兩者為unhashable) 宣告範例(四種建立方法) ``` a={1:42,(4,2):[30,74],5:'apple'} print(a[(4,2)]) b=dict({2:'a','6':2}) print(b['6']) c=dict([[10,6],['apple','orange']]) print(c['apple']) d=dict(zip((1,2),(3,8))) #1是3的key 2是8的key print(d[2]) ``` 輸出結果: ``` [30, 74] 2 orange 8 ``` **dict的方法(function)** **新增(修改)組合的方法** 容器名稱[想增加(修改)的key]=想增加(修改的value) **setdefault()** 尋找指定key值,並回傳對應的value,若該key值不存在,則建立此key值,value預設為None(或自訂的值) 使用方法: setdefault(n)代表尋找並回傳n所對應的value,若找不到則建立,其對應的value則為None setdafault(n,'apple')代表尋找並回傳n所對應的value,若找不到則建立,其對應的value則為'apple' **get()** 放入key值能,回傳對應value,與dict[]不同的是,當key值不存在,會回傳None(或是自訂回傳的物件),而非錯誤訊息 使用方法: get('a')代表回傳'a'為key值所對應的value get(n,10)代表回傳n為key值所對應的value,若沒有此key值,就回傳10 **clear()** 清空呼叫方法的dict內部,留下殼 使用方法: dict() **items()** 回傳一個二維list,內部為呼叫方法的dict的key以及對應的value值 使用方法: items() **keys()** 回傳一個list,內部為呼叫方法的dict的所有key值 使用方法: keys() **values()** 回傳一個list,內部為呼叫方法的dict的所有values值 使用方法: values() **pop()** 移除指定key值和所對應value,回傳該value值,若key值不存在,則跳出錯誤(或自訂的物件) 使用方法: pop(n)代表刪除n為key值和對應的value的組合 pop(n,'d')代表刪除n為key值和對應的value的組合,若n不在就回傳'd' **popitem()** 移除最晚被加入的組合(key-value),並回傳這個組合(tuple型態),若dict已空,則回傳錯誤訊息 使用方法: popitem() **update()** 將另一個dict的所有內容(key-value),加到呼叫方法的dict,若有重複的key值,則把另一個dict的value覆蓋上去 使用方法: update(mydict)代表將mydict的所有內容放入呼叫的dict內部 範例: ``` d={1:2} d.setdefault(1,20) d.setdefault(9,'b') print(d) d['66']=77 print(d) print(d.get(3,'Not Found')) print(d.get(9)) list1=d.items() print(list1) print(d.keys()) print(d.values()) k={1:11,4:'b'} d.update(k) print(d) ``` 輸出結果: ``` {1: 2, 9: 'b'} #d {1: 2, 9: 'b', '66': 77} #d Not Found b dict_items([(1, 2), (9, 'b'), ('66', 77)]) dict_keys([1, 9, '66']) dict_values([2, 'b', 77]) {1: 11, 9: 'b', '66': 77, 4: 'b'} #d ``` ## <p id="string">字串處理</p> ### 字串 可以用' '," ",''' '''去宣告一個字串 可以說是字元的容器,把字元裝在一起,並且允許使用[index]去存取,也能使用+去增加字串,但加入後不能修改內容 index為0,代表取index為0的位置(也是字串的第一位)的字元,若index為負,則代表從後面數來的第幾個,-1即代表倒數第一個 範例 ``` str='abc' print(str[0],str[1],str[2],sep='->') print(str[-1],str[-2],str[-3],sep='->') ``` 輸出結果: ``` a->b->c c->b->a ``` ### 字串加和乘 可以透過+來讓兩個字串聯接,也可以透過*讓字串重複 範例 ``` s1=' abc ' s2=' qwe ' s3=s1+s2 print(s3) s4=s1*2+' ; '+s2*3 print(s4) ``` 輸出結果: ``` abc qwe abc abc ; qwe qwe qwe ``` ### 進階中括號[]使用方法: [X:Y:Z] XYZ都必須為整數 X代表開始的index值,預設為0 Y代表結束的index值,預設為len(使用的字串),即字串長度,此外不會走到Y的位置 Z代表一次走多少位置,預設為1 走一次即從X開始最多走到Y-1的index位置,然後每次走Z個位置 範例 ``` s='abcde' print(s[1:3:1]) print(s[0:4:2]) print(s[-1:0:-1]) print(s[1::2]) print(s[:2:]) ``` 輸出結果: ``` bc ac edcb bd ab ``` --- ### String字串的常用方法(function) 只要變數是字串型態,都能呼叫這些方法 ### 字串變換(回傳新字串) **strip()從兩邊,lstrip()從左邊,rstrip()從右邊** 將字串將從最左或最右(往中間)清除指定的字元,直到不是要清除的字元為止,預設為清除空白,並回傳為一個新字串(原字串不會改變) 使用方法: strip()清除呼叫字串的最左邊最右邊,並回傳一個新的字串 strip('ab')清除呼叫字串的從最左邊和最右邊開始遇到的字元a和b,直到不是這兩個字元('ab'可以以一個字串變數代替) 範例 ``` s=' bBbaadBBb' s1=s.strip() print(s1) s2=s.strip('b ') print(s2) s3=s.lstrip('b') print(s3) s4=s.rstrip('b') print(s4) print(s) ``` 輸出結果: ``` bBbaadBBb #從兩邊清除空白 BbaadBB #從兩邊清除空白和b bBbaadBBb #從左邊清除b bBbaadBB #從右邊清除b bBbaadBBb #s不會被改變 ``` **swapcase()** 將字串變成大寫英文字母換成小寫,小寫英文字母換成大寫,並回傳為一個新字串 使用方法: swapcase() 範例 ``` s=' MOusE ' print(s.swapcase()) ``` 輸出結果: ``` moUSe ``` **capitalize()** 將第一個字母(必須放在字串最前面,即index為0的位置)轉換成大寫,其餘字母全轉成小寫,並回傳為一個新字串 使用方法: capitalize() 範例 ``` s='MOUSE' print(s.capitalize()) s=' MOUSE' print(s.capitalize()) ``` 輸出結果: ``` Mouse mouse ``` **title()** 將字串轉換為類似英文報紙或作品標題格式,即每個單字(中間有空格隔開)的第一個字母大寫,且其餘字母變成小寫,並回傳為一個新字串 使用方法: title() 範例 ``` s='hello wORLD!! THIS is Lancaster sPEaking' print(s.title()) ``` 輸出結果: ``` Hello World!! This Is Lancaster Speaking ``` **upper(),lower()** 將字串全部英文字母改為大寫(小寫),並回傳為一個新字串 使用方法: upper() lower() **zfill()** 放入指定長度,若長度大於原字串,將從字串左邊補上0,直到符合長度,否則不會有任何改變,並回傳為一個新字串 使用方法: zfill(n),若呼叫的字串長度小於n,把字串左邊補上0,直到長度為n,並回傳為新字串 範例 ``` s='aaa' print(s.zfill(1)) print(s.zfill(len(s)+4)) ``` 輸出結果: ``` aaa 0000aaa ``` ### 字串判斷(回傳bool真假值) **startswith(),endswith()** 檢查字串指定範圍內是否以指定字串為開頭(結尾),回傳一個真假值(bool),若沒打範圍,則預設為整個字串 使用方法: startswith('abc')檢查呼叫的字串是否為以abc為最前面三個字元 startswith('abc',2,7)檢查呼叫字串的index 2到index 6(不含7)是否以abc為前三個字元(即檢查index2是否為a index3是否為b index4是否為c) endswith('abc')檢查呼叫的字串是否以abc為最後三個字元 endswith('abc',5,14)檢查呼叫字串的index 5到index 13(不含14)是否以abc為最後三個字元(即檢查index11是否為a index12是否為b index13是否為c) 範例 ``` s='this is my pens' print(s.startswith('this')) print(s.startswith('this',5,10)) print(s.endswith('pen')) print(s.endswith('s',0,4)) ``` 輸出結果" ``` True False False True ``` **istitle()** 判斷字串內部是否每個單字的第一個字都是大寫,且其餘字母為小寫,回傳真假值(bool) (可用來判斷這個字串是否被title()過) 使用方法: istitle() 範例 ``` s='this Is my Pens' print(s.istitle()) s='THIS Is My PENS' print(s.istitle()) s='This Is My Pens' print(s.istitle()) ``` 輸出結果: ``` False False True ``` **isupper(),islower()** 判斷所有字母是否都為大寫(小寫),回傳真假值(bool) (可用來判斷字串是否被upper()或lower()過) 使用方法: isupper() 範例 ``` s='hello wORLD!!' print(s.upper().isupper()) #會先變成upper()過的新字串,再呼叫isupper()的方法 ``` 輸出結果: ``` True ``` **isalnum()** 判斷呼叫的字串裡面是否只含a~z和A~Z和0~9這些字元,若是多行字串裡面必有'\n'(換行字元),因此必為false,回傳真假值(bool) 使用方法: isalnum() 範例 ``` s='hello AZ123' print(s.isalnum()) s='helloAZ123' print(s.isalnum()) ``` 輸出結果: ``` False #空格不屬於該範圍,所以為false True ``` **isalpha()** 判斷呼叫的字串裡面是否只有英文字母,回傳真假值(bool) 使用方法: isalpha() 範例: ``` s='aa bb' print(s.isalnum()) s='aabb' print(s.isalpha()) ``` 輸出結果: ``` False True ``` **isdigit()** 判斷呼叫的字串是否為數字,回傳bool值 可以搭配eval()使用,先判斷字串是否為數字,在在使用eval()轉成數字型態,這樣可以避免eval()產生錯誤 使用方法: isdigit() 範例: ``` s='731' if(s.isdigit()): x=eval(s) print(x) else: print('該字串不是數字') ``` 輸出結果: ``` 731 ``` **isspace()** 判斷呼叫的字串裡面的所有字元是否為只有空白字元的字串 使用方式: isspace() 範例: ``` s=' ' print(s.isspace()) s=' 4 ' print(s.isspace()) ``` 輸出結果: ``` True False ``` ### 字串切割及尋找 **split()** 將字串根據條件切成多個小字串,回傳list,裡面為切割好的小字串,小字串至少會有一個字元存在 可以使用的傳入參數有兩個: * sep可以設定遇到怎樣的字元或字串要切割,若沒設定,則預設為單個空白 * maxsplit可以設定回傳的list最多使用到第幾個index值,代表可以限制切割的小字串數量,若沒設定,則預設為切到字尾(設為1代表最多只能使用到index為1,即代表只有兩個小字串)(maxsplit的值+1即為結果的小字串數量) 使用方式: split()代表遇到空白就會切,且切到字尾為止 split(sep='a')代表遇到a就會切割字元,且切到字尾為止,此外也可以直接打成split('a') split(sep='man',maxsplit=3)代表遇到man就會切割字元,且最多只能使用到index為3個位置,即只會有4個小字串(index0~3),此外也可以直接打成split('man',3) 範例 ``` s1='I am iron I am man!' s2='' list1=s1.split() for str in list1: print(str) s2+=str print(s2) list2=s1.split(sep='am',maxsplit=1) print(list2) ``` 輸出結果: ``` I am iron I am man! IamironIamman! #將且割完的小字串接到一起 ['I ', ' iron I ``` **splitlines()** 將多行的字串切成一行一行的並回傳一個list裡面為每一行的字串 使用方法: splitlines() 範例 ``` s='abc abd \n afff \n dadad ' print(s.splitlines()) ``` 輸出結果: ``` ['abc abd ', ' afff ', ' dadad '] ``` **partition()** 將字串根據指定字元或字串切割成三部分,並回傳為空間為3的tuple,且只會切第一個符合的,若找不到則回傳的tuple的index0為原字串,而後面兩個位置為''(空字串),此外與split()不同的地方,除了一定只切一次,還有會保留指定的字元或字串 使用方法: partition('bad')代表遇到bad就切為三部分 範例 ``` s='an apple is here' t=s.partition('b') print(t) t=s.partition('is') print(t[0],t[1],t[2],sep='\n') ``` 輸出結果 ``` ('an apple is here', '', '') an apple is here ``` **count()** 尋找指定字元或字串在呼叫的字串裡面出現幾次,並回傳為一個整數 此外能設定搜尋的範圍index,預設的範圍就是全部字串 使用方法: count('qq')代表從頭開始尋找qq直到最後,並回傳找的次數 count('apple',5)代表從index5開始尋找apple直到最後,並回傳找的次數 count('b',1,8)代表從index1搜尋到index7(8-1)尋找b,並回傳找的次數 範例 ``` s='abc abd acd bca ba' print(s.count('ab')) print(s.count('a',5)) print(s.count('a',5,8)) ``` 輸出結果: ``` 2 3 0 ``` **find(),index()** 尋找指定字元或字串第一次出現的index值(字串的情況就傳第一個字元出現的index位置),跟count()一樣也能設定範圍,且規則一樣 這兩個方法不同的地方在於find()找不到的時候是回傳-1,而index()則是回傳一個錯誤的訊息 使用方法: find('a')代表找從頭到尾找第一個出現a的index值,找到就回傳,否則回傳-1 find('b',6)代表從index6找到最後,找到就回傳,否則回傳-1 find('ple',2,15)代表從index2找到index14(15-1),找到就回傳該位置裡面p的index值,否則回傳-1 範例 ``` s='abc abd acd bca ba' print(s.find('ab')) print(s.find('ab',2)) print(s.index('ab')) print(s.index('ab',2)) print(s.find('a',5,8)) ``` 輸出結果: ``` 0 4 0 4 -1 ``` --- ## <p id="function">函數</p> 除了物件本身可以呼叫的函數(方法),我們也可以自訂函數,而好處就在於可以讓特定功能重複被使用,每次要使用時,只要呼叫函數就行,此外要注意的是,必須先定義函數才能呼叫,所以函數定義最好寫在程式碼前部分 函數的可以分為四部份: * 回傳值:呼叫函數完後要回傳的變數或值,可以用逗號來回傳多個,也可以不回傳值,但會變成自動回傳None物件 * 函數定義:函數的內容,且要縮排,函數內部新宣告的變數都是區域變數 * 參數:呼叫函式時,要使用的變數,也可以不傳入任何參數,有順序性,屬於區域變數,傳入時,會依 照順序,否則必須打上參數名稱 * 函數名稱:用來呼叫函數 <p><b>當傳入參數太多時,為避免要命名很多參數名稱,可以使用*將眾多變數放在同一個tuple或使用**將其放在同一個dict</b>,使用方法即是在參數前面打上*或**</p> **return的功用** return除了可以回傳值,還有跳離函數的功用,代表只要在函數中執行return,函數就會直接回到呼叫的地方,而不管函數是否執行完,所以只要函數已經執行到我們想要的部分完就能使用return了,就如同迴圈中的break,此外也可以不使用任何return,如同迴圈沒有break,這樣只要函數全部執行完,就會回到呼叫的地方 自訂函式的方法: ``` def 函數名稱(參數名稱,參數名稱...): 函數內容 ... return 要回傳的物件1,要回傳的物件2.. ``` 範例(先定義好myfunction再呼叫) ``` def myfunction(a,b): #a和b即為參數 c=a+b d=a*2+b*2 return c,d #c和d為回傳值 num1=10 num2=20 print(myfunction(num1,num2)) #num1和num2為引數,沒打上參數名稱,照順序給參數 s1='apple' s2='cat' print(myfunction(b=s1,a=s2)) #s1和s2為引數,並打上參數名稱 ``` 輸出結果: ``` (30, 60) ('catapple', 'catcatappleapple') ``` 範例(return可以有多個,且沒回傳值時,會回傳None,此外在這個範例中,最後的return可以省略) ``` def myfunction(a,b): a=a+b if a>10: return True return print(myfunction(5,8)) print(myfunction(4,2)) ``` 輸出結果: ``` True None ``` 範例(將多個參數變成一個tuple或dict) ``` def myfunction1(*a): ans=0 for num in a: ans+=num return ans def myfunction2(**a): for element in a: print('%s\'s score:%d'%(element,a[element])) print(myfunction1(46,34,87,63,10,28,92)) myfunction2(Mary=52,Ken=84,cindy=90,Leo=40) ``` 輸出結果 ``` 360 Mary's score:52 Ken's score:84 cindy's score:90 Leo's score:40 ``` ### 參數vs引數 **參數**是在函數括號內部的區域變數,且當函數結束就會消失,且不能再函數外使用的變數。 **引數**則是呼叫函數時,給函數當作內部參數要複製值的對象 所以當參數值改變不會影響引數的值,但如果參數的型態為容器,則會影響同為容器型態的引數 ### pass by reference傳址(傳參考) vs pass by value傳值 在參數引數之間的關係可以分為這兩種 傳址:把引數的記憶體位置傳給參數,參數改變會影響引數,當參數是容器才會使用傳址 傳值:把引數的值複製給參數,而使用不同記憶體空間,參數一般都是傳值 範例 ``` def myfunction(a,b): a[0]=500000 b=100 list1=[50] num=20 myfunction(list1,num) print(list1,num) ``` 輸出結果: ``` [500000] 20 ``` ### 預設參數 要是參數沒有得到可以複製值得對象的情況,我們可以令它為一個預設的值來避免錯誤,若變數沒有預設的值,就代表呼叫的時候必須給它引數,此外在宣告的括號裡面,有預設值的參數數要在沒預設值的參數後面 ``` def 函數名稱(參數名稱,參數名稱=預設的值...): 函數內容 ... return 要回傳的物件1,要回傳的物件2... ``` 範例 ``` def myfunction(a=30,b=2): return a/b num1=10 num2=20 print(myfunction()) print(myfunction(num1)) print(myfunction(num1,num2)) ``` 輸出結果: ``` 15.0 5.0 0.5 ``` ### 全域變數在函數中和global 在自訂函數中若沒有變數名稱與全域函數名稱相同,可以存取全域變數的值,但不能修改,除非先加入global定義全域變數 使用方法: global 全域變數名稱 此外若該全域變數不存在,這樣就等於直接在自訂函數中宣告了一個全域變數,但如果這個函數沒被呼叫,那也是沒宣告到 範例 ``` a=1 def func1(): global a a = 99 def func2(): global b b=31 func1() func2() print(a,b) ``` 輸出結果: ``` 99 31 ``` --- ## <P id = 'mod'>模組</P> 模組是一種.py檔,用來保存程式碼,好處在於可以把常用的函數或是類別甚至是變數保存起來,隨時引入即可使用。 ### 引入模組 要先引入想使用的模組才能使用其內部程式 **引入方法1**(整個引入): ``` import 模組名稱1,模組名稱2... ``` **引入方法2**(部分引入,只引入某部分程式碼): ``` from 模組名稱 import (類別/函數/變數)名稱1,名稱2... ``` 方法2引入的東西不需要模組名就能直接呼叫 **引入方法3**(將所有引入,但也可以不用模組名就能呼叫) ``` from 模組名稱 import * ``` **注意** 雖然方法2和方法3使用起來比較方便,但是若原程式有同的名稱的東西可能會造成被覆蓋,所以得僅慎使用 範例 ``` import time from math import pi,sqrt print(pi,sqrt(25)) #使用方法2因此不用模組名就能使用 print(time.gmtime()) #使用方法1因此要模組名才能呼叫 ``` 輸出結果: ``` 3.141592653589793 5.0 time.struct_time(tm_year=2021, tm_mon=7, tm_mday=16, tm_hour=6, tm_min=47, tm_sec=29, tm_wday=4, tm_yday=197, tm_isdst=0) ``` 此外模組的py檔必須在sys.path裡面,sys.path有好幾條路徑,他會依序尋找 可以透過執行下面程式知道sys.path ``` import sys print(sys.path) ``` **as** 要呼叫模組的東西必須先打上模組名稱.要呼叫的東西,若模組名太長會比較麻煩,因此在import時,可以用as使模組名被取代,這樣可以避免模組名太長,甚至把模組名改成方便使用的,但不會真的更改模組實際名稱,只會影響這支程式(import模組的程式)裡面的模組名稱,此外使用as後就不能使用原模組名稱 ``` import 原模組名稱 as 想要的模組名稱 ``` ### 常用官方模組 官方標準的模組通常都跟python一起裝好了,所以直接import就可以使用 下面列舉幾個常用模組和裡面常用函數 此外除了官方,也有其他人開發的模組(第三方模組)可以使用,但必須額外安裝 #### **time** [官方說明網頁](https://docs.python.org/3/library/time.html?highlight=time#module-time) **time.sleep(秒數)** 可以使程式暫停幾秒 **time.localtime()** 回傳本地時間 **time.gmtime()** 回傳UTC世界標準時間 --- #### **random** [官方說明網頁](https://docs.python.org/3/library/random.html) 產生亂數的模組,但不適合用來產生密碼 **random.randint(最小值,最大值)** 回傳一個隨機整數,**大於等於**最小值且**小於等於**最大值 **random.randrange(值1,值2,差)** 回傳一個隨機整數,介於值1和值2,但永遠不會為值2,當差>0 值2要大於值1,當差<0,值2要小於值1,此外差必須為整數,差影響的是亂數產生的間距 亂數產生的公式 亂數=值1+整數隨機亂數*差 範例 ``` import random print(random.randrange(2,8,3)) #可能產生的數:2 5 2=2+0*3 5=2+1*3 print(random.randrange(6,-2,-3)) #可能產生的數:6 3 0 6=6+0*(-3) 3=6+1*(-3) 0=6+2*(-3) ``` 輸出結果: ``` 5 3 ``` **random.random()** 回傳一個**大於等於**0且**小於**1的隨機浮點數 **random.uniform(最小值,最大值)** 回傳一個**大於等於**最小值且**小於等於**最大值的隨機浮點數 **random.choice(容器或字串)** 從有順序性的容器(list,tuple,range)或字串隨機選出一個成員 範例 ``` import random a='afqwert' b=(1,'saa',78) c=[4,2,'pe'] print(random.choice(a)) print(random.choice(b)) print(random.choice(c)) ``` 輸出結果 ``` r 1 pe ``` **random.sample(容器或字串,隨機的不重複的數量)** 從有順序性的容器(list,tuple,range)或字串隨機選出指定數量且不重複的成員,跟排列組合裡面的C一樣,並回傳為一個list 範例 ``` import random a='afqwert' b=(1,'saa',78,99) c=[4,2,'pe'] print(random.sample(a,2)) print(random.sample(b,3)) print(random.sample(c,2)) ``` 輸出結果: ``` ['a', 'f'] [1, 99, 'saa'] [2, 4] ``` **random.shuffle()** 將list裡面的順序重新隨機洗牌,會直接改變list的順序,不回傳任何值 範例 ``` import random c=[4,2,'pe','kk','gg',74] random.shuffle(c) print(c) ``` 輸出結果: ``` [74, 4, 2, 'pe', 'gg', 'kk'] ``` --- #### **os** [官方說明網頁](https://docs.python.org/3/library/os.html?highlight=os#module-os) 有一些系統上的操作指令函數 注意以下路徑或檔案名稱都是用字串型態傳入 此外這邊的檔案路徑可分為絕對路徑和相對路徑 **絕對路徑**就是從完整的路徑,但是必須把/改成//來辨識為絕對路徑,例如C:\\Users\\User\\Desktop\\python\\hello.txt **相對路徑**就是依照os.getcwd()得知當前的目錄,再以這個為基礎去給相對的路徑,假如當前路徑是:C:\\Users\\User\\Desktop,那hello.txt的相對路徑,就會是\pyhton\hello.txt **..\\** 在相對路徑中可以達到回上一層的功能 **os.getcwd()** 回傳當前目錄位置 **os.chdir(路徑)** 切換當前目錄到該路徑下 **os.rename(目標,新名稱)** 對目標檔案或資料夾改名 **os.remove(檔案路徑)** 專門用於刪除檔案 **os.removedirs(資料夾路徑),os.rmdir(資料夾路徑)** 專門用於刪除**空的**資料夾,不是空的不能刪除 **os.listdir(路徑)** 列出路徑下的所有資料夾和檔案 **os.mkdir(路徑)** 建立新的資料夾,路徑不打就是在當前目錄建立新資料夾 **os.path.getsize(路徑)** 回傳檔案大小 **os.path.getctime(路徑)** 回傳檔案建立的日期 **os.path.getmtime(路徑)** 回傳檔案修改的日期 **os.path.getㄇtime(路徑)** 回傳檔案存取的日期 **os.path.isfile(路徑)** 檢查路徑是否為一個檔案,回傳真假值 **os.path.isdir(路徑)** 檢查路徑是否為一個資料夾,回傳真假值 **os.path.exists(路徑)** 檢查路徑的資料夾或檔案是否存在,回傳真假值 **os.system('...')** 可以開啟命令提示字元並執行''裡面打的命令 ### 自訂模組 可以編寫自己的模組,來作為常用的工具,此外,在自訂模組中,也可以引入其他模組來使用 範例 mylib.py(自己編寫的程式,計算園面積,以及使用餘弦定理計算第三邊) ``` import math pi=3.1415926 #其實math裡面就有標準的pi了 def area(r): return r*r*pi def getTheThird(b,c,degree): return math.sqrt(b*b+c*c-2*b*c*math.cos(degree*math.pi/180)) ``` test.py ``` import mylib as m print(m.area(5)) print(m.getTheThird(3,4,90)) ``` 輸出結果: ``` 78.539815 5.0 ``` --- ## <p id = "file">檔案處理</p> 檔案處理的好處在於。可以將資料放在其他檔案中,而不用預先寫進程式碼,或是將程式執行結果寫進一個檔案中保存,此外這裡的檔案是**txt檔** ### 檔案處理的步驟一 開檔 開檔的目的在於先知道目標的檔案,才能在做第二步驟的存取 **開檔方式**為使用一個變數去當作接收open()回傳的檔案物件 ``` 變數名稱 = open(檔案路徑,存取模式,資料讀入的暫存空間) ``` **檔案路徑** 可以用相對路徑或絕對路徑(在官方模組os的說明有解釋過了,可以往上找尋),此外檔案的副檔名.txt也要有 **存取模式** 讀取模式可決定你可以對檔案做出怎樣的操作,此外傳入此參數時候要用字串型態,若不打則預設為r * r 以唯讀模式開啟檔案並**從頭**開始讀取,不能對檔案作和和更改, * r+ 以同時能讀和寫模式開啟檔案並**從頭**開始,可能會覆蓋原有的資料 * w 以寫入模式開啟檔案並**從頭**開始寫入,會覆蓋原有的資料 * w+ 以同時能讀和寫模式開啟檔案並**從頭**開始,可能會覆蓋原有的資料 * a 以寫入模式開啟檔案並從**最後**開始寫入,因此不會覆蓋到原有資料 * a+ 以同時能讀和寫模式開啟檔案並從**最後**開始 **w+和r+的不同**,w+會將檔案完全的清空覆蓋上新的資料(即使沒做步驟二的任何操作),r+不會將檔案清空,會依照新的資料若用到舊的位置,才覆蓋上去 當檔案不存在時,r/r+會傳錯誤訊息,而w/w+/a/a+則會建立新檔案 如果是在讀二進位檔案必須在讀取模式的字後面加b,例如rb,a+,wb+...等 **資料讀入的暫存空間** 以數字方式傳入,功用為決定一次能讀取的資料行量,0代表沒有暫存空間,-1代表使用預設的暫存空間,其他數字則能代表為一次能讀幾行的暫存空間,**通常可以不打這個參數**,讓它使用預設的就好 ### 檔案處理的步驟二 寫檔或讀檔 根據步驟一的存取模式決定是寫檔或讀檔,此外需要注意檔案的游標位置,會決定讀取或寫入的東西,游標過了的地方就不會被影響了 #### **讀檔** 將檔案內容讀進來,此外要注意的是,可以混和使用,但是讀過的地方就不會再讀了因為游標已經過去了 使用方法:**檔案的變數物件.函數** read() 將檔案全部內容讀進,並回傳為一個字串 readline() 將檔案讀一行,並回傳為一個字串 readlines() 將檔案一行一行讀成一個字串直到讀完,並回傳為一個list,內部每個index為每一行 範例 data.txt ``` hello world!! today monster ``` 程式碼 ``` f=open('data.txt','r') result=f.read() print(result) f.close() f=open('data.txt','r') print(f.readline()) print(f.readlines()) f.close() ``` 輸出結果: ``` hello world!! today monster hello world!! ['today\n', 'monster'] ``` #### **寫檔** 將資料寫入檔案 使用方法:**檔案的變數物件.函數** write() 將字串型態的資料寫入檔案(只能傳入字串),不會自動換行 writelines() 將內部全部都是字串的list寫入檔案(只能傳入list),不會自動換行,每個字串會直接連載一起,想換行必須在自己加'\n' 範例 data.txt ``` hello world!! today monster ``` 程式碼 ``` f=open('data.txt','r+') lst=['apple','bad\n'] f.write('pppppp') f.writelines(lst) f.close() ``` 輸出結果: data.txt ``` ppppppapplebad oday monster ``` ### 檔案處理的步驟三 關檔 當結束存取後,必須要關檔,這樣才能保存存入的資訊,或是避免檔案被鎖定,不能被更動的下場 關檔方式 ``` 檔案物件變數.close() ``` --- ## <p id="exception">例外處理</p> 當程式發生錯誤就會跳出對應的錯誤訊息並且中止程式,例外處理可以讓錯誤發生時,不中止程式,並可以做出適當的處理 例外處理方法 當程式碼發生錯誤就會往下找到第一個符合的例外情況 else和finally可以省略 ``` try: 程式碼(可能產生錯誤的程式碼) ... except 例外情況1(可能發生的錯誤訊息): 當符合這個例外情況1要執行的程式碼 ... except 例外情況2(可能發生的錯誤訊息): 當符合這個例外情況2要執行的程式碼 ... else: 當程式沒有發生任何錯誤,要執行程式碼 ... finally: 當上面全部都執行完,都會要執行的程式碼 ... ``` 範例 ``` try: int('aphd') except ValueError: print('無法轉換為數字') else: print('轉換成功') finally: print('程式執行完畢') try: int('412') except ValueError: print('無法轉換為數字') else: print('轉換成功') finally: print('程式執行完畢') ``` 輸出結果: ``` 無法轉換為數字 程式執行完畢 轉換成功 程式執行完畢 ``` ### 得知錯誤訊息 可以藉由故意犯錯來知道錯誤訊息 例如 開檔未找到的錯誤 ![](https://i.imgur.com/DA6XTlJ.png) 得知當檔案無法找到會跳出FileNotFoundError --- ## <p id="class">類別(class)</p> 在python裡面所有東西都是物件,但物件和物件之間的不同是源自於類別,類別就是物件定義的地方(模板),物件則是類別被實例化的結果,如同狗如果是一種類別,那人養的哈士奇,臘腸狗,柯基都是物件。 類別是定義物件的地方,因此有兩個地方可以被定義,一個是類別的屬性變數,一個是類別的函數,當一個物件被實例化後就能使用這些已經在類別被定義好的東西 ### 建構式 建構式是只有當物件被建立時回呼叫的函數,可以用來初始化物件的變數或是做一些函數的呼叫。 使用方法為在類別中定義(繼承)__init__然後就能使用這個建構式,當類別的物件被創立就會自動呼叫它了,還可以決定傳入的參數 ### 解構式 解構式是當物件沒被使用的時候(即已經沒有直接呼叫辦法可以使用此物件),會呼叫解構式並刪除物件 使用方法為在類別中定義(繼承)__del__然後就能使用這個解構式,當類別的物件被刪除就會自動呼叫它了 ### 類別變數VS實體變數 在類別中類別變數是直接取名並使用的,而物件各自的變數(實體變數)是必須先加上self.變數名稱才能宣告,而且類別變數屬於都來自這個類別的物件,因此是共用的,而實體變數則是每個物件各自的變數 此外類別變數可以被同類別的物件使用或呼叫,但是若有實體變數和類別變數相同名稱,會優先呼叫為實體變數 ### 在類別中自訂函數 如同一般的自訂變數的使用方法,不同的地方在於,傳入參數第一個必須是self,而且這個自訂變數只能被這個類別的物件呼叫使用 範例: ``` import random class Robot: centerX=0 #類別變數 centerY=0 #類別變數 def __init__(self,x,y): #建構式,並增加兩個傳入的參數x和y self.x=x #建立兩個實體變數 self.y=y def getLocation(self): return[self.x,self.y] def getCenter(self): return(Robot.centerX,Robot.centerY) def up(self,num): self.y+=num def down(self): self.y-=1 def right(self,num): self.x+=num def left(self): self.x-=1 def randomCenter(self): #隨機改變類別變數 Robot.centerX=random.randint(0,10) Robot.centerY=random.randint(0,10) robot1=Robot(9,7) #建立物件,傳入引數9,7給建構式的x和y robot2=Robot(1,1) #建立物件,傳入引數1,1給建構式的x和y robot1.up(4) print(robot1.getLocation()) robot1.right(7) print(robot1.getLocation()) for i in range(3): robot1.down() print(robot1.getLocation()) for i in range(1): robot1.left() print(robot1.getLocation()) print('center:',robot2.getCenter()) #用robot2呼叫函數印出類別變數 robot1.randomCenter() #用robot1打亂類別函數 print('center:',robot2.getCenter()) #用robot2呼叫函數印出類別函數,證明為共用 print('center:',robot2.centerX,robot2.centerY) #用物件名直接呼叫類別函數 ``` 輸出結果: ``` [9, 11] [16, 11] [16, 8] [15, 8] center: (0, 0) center: (10, 9) center: 10 9 ```