# Python function 函式呼叫 / 錯誤例外處理 exception 學習如何看懂Python官方手冊,以及語法規則,職訓所課堂筆記。 > [TOC] --- 臨時整理區: 魔法函式 `__name__ == "__main__"` 直接執行而非被載入 https://pythonbook.cc/chapters/basic/module-and-package#被匯入-vs-直接執行 --- <!-- [Python 課堂講義筆記](https://absorbing-bookcase-ffc.notion.site/2024-07-31-79b30c36611940e9bec9ab1f23d957fa) --> # 呼叫規則 先定義好 function ``` def func(區域參數): 主要程式 return 返回值 ``` ```python= # 參數可設預設值,必須固定值 def twoSum(a, b = 5): """ 兩個數字加起來 """ c = a + b return c ``` 調用函式 ```python= # 參數傳遞 a,b a, b = 2, 3 ans = twoSum(a, b) print(ans) ``` ## 局部引數 ```python= def print_test(): mes = "god" print(mes) print_test() # print(mes) 無法從外部呼叫 ``` 不行設定成可變物件 mutable object > 課後作業:什麼是 mutable? 必須指向不可變對象 > 預設值盡量不要用空串列或字典 ```pyhton= def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print(f(3)) # 輸出 [1] [1, 2] [1, 2, 3] ``` 需改成 ```python= def f(a, L=None): if L is None: L = [] L.append(a) return L print(f(1)) print(f(2)) print(f(3)) # [1] # [2] # [3] ``` ## 全域引數 ```python= mes = "god" def print_test(): global mes mes = "變更參數" print(mes) print_test() print(f"再次查看:{mes}") 變更參數 再次查看:變更參數 ``` # 有內定鍵值的引數 有內定值的引數要放在後面 https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments * 位置對應引數 postion arguments * 關鍵字對應引數 keyword(s) arguments 沒講清楚,預設對位置 混合使用,需要先對位置再用 keyword ```python= def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ') print("if you put", voltage, "volts through it.") print("-- Lovely plumage, the", type) print("-- It's", state, "!") # parrot("123", state=1000) ``` # 不固定數量引數 查找語法手冊看到: `breakpoint(*args,**kws)` 可變引數(\*args 和 \*\*kwargs) (有先後順序,先一顆星,再來兩顆星) * 一顆星 包住 元組 (a,b) * 兩顆星 包住 字典 {key:value} (感覺很高手的做法,竟然可以把 key 傳入變成字典) 字典跑迴圈,拿出來的是鍵值 key 可以再用 `key` 取值,`dic[key]` * 提醒 key 只能是字串,元素,元組 ```python= def func(a,*t, **d): for i in range(a): print("*") print(t) print(d) for key in d: print(key,d[key]) func(4,"abc","def","ghi",k=1,m=2) # * # * # * # * # ('abc', 'def', 'ghi') # {'k': 1, 'm': 2} # k 1 # m 2 ``` ```python= def cheeseshop(kind, *arguments, **keywords): print("-- Do you have any", kind, "?") print("-- I'm sorry, we're all out of", kind) for arg in arguments: print(arg) print("-" * 40) for kw in keywords: print(kw, ":", keywords[kw]) ``` ```python= def add_all(*add): result = 0 for i in range(len(add)): result += add[i] return result print(add_all(1, 2, 3, 4, 5)) # 15 ``` # 特殊參數 Special parameters https://docs.python.org/3/tutorial/controlflow.html#special-parameters **範例:** ```python def func(pos1, pos2, /, pos_or_kwd, *, kwd_only): print(pos1, pos2, pos_or_kwd, kwd_only) func(1, 2, 3, kwd_only=4) # 正確 func(1, 2, pos_or_kwd=3, kwd_only=4) # 正確 # func(1, 2, 3, 4) # 錯誤:kwd_only 只能作為關鍵字參數 ``` **Argument 跟 Parameters 翻譯差異推論** - **Parameter(參數)**:函數定義時列出的變數名稱,用來函數呼叫時提供的值。 `def func(a, b=5):`,`a` 和 `b` 是參數。 - **Argument(引數)**:函數被呼叫時實際傳入函數的值。`func(10, 20)` 中,`10` 和 `20` 是傳入的引數。 ``` 我的練習推論: e.g : `discord.py` 模組 ctx ---> 作為引數 argument,傳遞上下文 模組底下可以用的方法 run 可以帶入的參數 Parameter https://discordpy.readthedocs.io/en/stable/api.html?highlight=get%20channel#discord.Client.get_channel ``` 三個區域的參數規則 (__第一個__ / 第二個區域 *,__第三個_) pos only / pos or keyword *, keyword only 例如 BIF函式 > max(iterable, *, key = None) >print(_*objects_, _sep=' '_, _end='\\n'_, _file=None_, _flush=False_)[¶](https://docs.python.org/3/library/functions.html#print "Link to this definition") >print(1,2,3) # 123都給object 星號代表全收 >那要怎麼設定後面的參數 >print(1,2,3,sep="#") >sort(對位置/,*,key=None) # Unpacking 解包,用更精簡的表達方式取出資料 ``` args = [3, 6] list(range(*args)) ``` [`range()`](https://docs.python.org/3/library/stdtypes.html#range "range") function https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists https://zhuyinjun.me/2019/python_unpacking_and_packing_1/ https://www.learncodewithmike.com/2019/12/python-unpacking.html > 課後作業:什麼是 packing unpacking? > 課後作業:什麼是 mutable inmutable? 留作自學,課堂並未教學 # Documentation Strings Pycharm 會提示你怎麼使用,就是使用 doc-strings ```python= def func(x): """ :param x: it means.... :return: """ match x: case "最小的": return 5 case 2: return 4 case 3: return 3 case 4: return 2 case "最大的": return 1 max(["最小的",2,3,4,"最大的"], key=func) # 年紀最小的 ``` # 例外處理 錯誤類型 分成兩大類: 語法錯誤 與 邏輯錯誤 try...except 是處理邏輯錯誤 > for 迴圈正常結束後 else 才會繼續做 > if 不成立後才執行 else > try...無錯誤...才執行 else Python Errors and Exceptions: https://docs.python.org/3/tutorial/errors.html Python 所有錯誤資訊: https://docs.python.org/3/library/exceptions.html#exception-hierarchy Python 例外處理教學文章: https://steam.oxxostudio.tw/category/python/basic/try-except.html https://ithelp.ithome.com.tw/articles/10262492 錯誤訊息: ![截圖 2024-08-16 上午10.27.33](https://hackmd.io/_uploads/ByC3Y42qR.png) 常見錯誤類型 | 錯誤資訊 | 說明 | | --- | --- | | NameError | 使用沒有被定義的對象 | | IndexError | 索引值超過了序列的大小 | | TypeError | 數據類型 ( type ) 錯誤 | | SyntaxError | Python 語法規則錯誤 | | ValueError | 傳入值錯誤 | ## Try...Except ``` a = "1" try: a += 1 print(a) except TypeError: print('型別發生錯誤') except NameError: print('使用沒有被定義的對象') print('hello') ``` ``` def func(a,b): try: c = a/b # return c except ZeroDivisionError: print("Division by zero") except Exception as e: print("包山包海",e) else: print("else:") return c finally: print("會執行") ``` ## Raise 自我拋出錯誤 ``` def func(num): try: # 要進行錯誤捕捉的程式碼 x = int(input("輸入小於十的正整數: ")) num += x # x += a # 錯誤測試 if x > 10 or x < 0: raise ValueError("您輸入的數字必須小於十的正整數") #主動拋出錯誤 except NameError as e: print("使用沒有被定義的參數 !", e) except TypeError as e: print("參數資料類型格式錯誤 !", e) except ValueError as e: print("資料傳入錯誤", e) except KeyboardInterrupt as e: print("程式被用戶中斷", e) except EOFError as e: print("未預期的結束輸入", e) except Exception as e: print("總之就是錯了", e) else: # 沒有錯誤,就會執行這裡 print(num) finally: # 不管有沒有錯誤都會執行這裡 print("一定執行") ``` ## Pass 不做任何動作...略過 (非 return) ## Assert > assert False, "錯誤訊息" ## Finally 程式註解文字引用來源: https://chwang12341.medium.com/給自己的python小筆記-debug與測試好幫手-嘗試try-except與主動引發raise與assert-程式異常處理-de0099d32bbe ```python= try: 要進行錯誤捕捉的程式碼 except 錯誤類型a as e: ##e 是用來記住錯誤資訊,可以不寫 如果程式發生錯誤類型為a,就會執行這裡 except 錯誤類型b: 如果錯誤類型為b,就會執行這裡 except (錯誤類型c, 錯誤類型d) as f: ## 用來同時捕捉多個錯誤 如果錯誤類型符合錯誤類型c與錯誤類型d,就會執行這邊 except Exception as e: 如果不知道會發生的錯誤類型為何,可以使用它,除了你寫下要捕捉的錯誤類型,其餘發生的錯誤都會執行這裡 else: 如果沒有錯誤,就會執行這裡 finally: 不管有沒有錯誤都會執行這裡 ``` ## 冷知識:當參數設定為 "e" 時 https://youtube.com/shorts/Yo6KSHdImkQ?si=W1nnkXYYXPcp2Tuo ## 單元測試框架 unittest https://docs.python.org/zh-tw/3/library/unittest.html ( 高階使用者使用,日後學習,for 考試先記住規則 ) ![截圖 2024-08-19 上午11.14.48](https://hackmd.io/_uploads/Skqh_VljC.png) 類別 大寫字母開頭(繼承類別): def 方法: def 方法: > self.assertIsInstance(obj, cls, msg=None) <!-- 實際範例: --> # Return return 返回一個( 任何物件 ) 可以是字串,可以是串列,可以是陣列 發現到特別之處,finally 會在 return 前執行。 ``` def count(a): try: a += 1 except Exception as e: print("發生異常:", e) else: return a finally: print("最後執行") print(count(1)) ``` > else 只能接在 except 之後 > finally 會在 return 前執行,finally 若有 return 會覆蓋前面的 return > 官方手冊案例:只使用 try 跟 finally > ~~(沒有人會這樣寫吧)~~ > (考題若出答案選錯誤,try 一定要配 except) https://docs.python.org/3/tutorial/errors.html#defining-clean-up-actions