Function and Data Structure 張傑帆 Chang, Jie-Fan
函數定義 函數傳遞參數與回傳值 區域變數與全域變數
包函許多程式碼的一行程式 ( 用來代表某種功能 ) 當程式碼太多且會重覆出現時, 可以將部份程式碼抽離主程式, 寫成一段函式, 有需要用到時再去呼叫它 函數是經過組織且可重複使用的程式碼, 是能用來實現單一或是相關聯的程式碼 巧妙的運用函數可以提高程式碼的重複利用率, 避免一樣的事情卻需要重複寫好幾次的程式碼來執行 這跟迴圈的概念有點像, 都是在重複利用程式碼 ; 不同的地方在於函數是在需要時才呼叫使用
Python 已經內建許多好用的函數, 例如 input() print() 等等 Python 內建函數是常用到的功能, 如果想要客製化的功能, 還是可以自己動手做, 執行一些工作, 或是進行計算 定義函數使用關鍵字 (keyword) def, 其後空一格接函數的識別字 (identifier) 名稱加小括弧 (), 然後冒號 : 其從屬內容必定要縮排如 : def function_name(): 縮排 #do something
函式定義從 def 開始函式名稱傳入參數 def get_final_answer(filename): 縮排 說明文字 line line return total_counter 冒號 縮排很重要若是沒有縮排的話會被認為是不屬於此函式的敘述 關鍵字 return 代表要回傳給呼叫者的值 函式內的變數是獨立的, 不會受外在變數的影響 不需標頭檔, 也不需宣告函式回傳值與參數型態
Hello_func.py 4 5 6 7 8 9 0 def >>> before hello hello hello hello after hello hello hello hello None last hello <function hello at 0x0D7F08> >>> 沒有回傳值的函數, 呼叫 (call) 該函數會自動回傳 None 物件 (object)
函數的小括弧可以定義參數 (parameter) 是提供給函數計算的數值 (value), 或是物件 (object) 函數 (function) 可以有回傳值 (return value) 回傳值可以是函數最後的計算結果 Function.py 90 4 5 6 7 8 9 0 90 90 >>> 0 50 F(0, 50) = 90 >>>
注意先有函數定義, 才可進行函數呼叫 Call_error.py 4 5 因為 Python 直譯器從頭一行一行的解譯程式原始碼 (source code), F() 既非 Python 的內建名稱, 也還沒解譯到底下定義的部份, 因此直譯器 直接發生 NameError, 終止程式的進行
用函數撰寫一程式, 令其計算 n*m 包含了兩個傳入值 n, m 練習一 不需回傳值, 直接在函數內將相乘的結果印出 練習二 有回傳值, 將相乘的結果回傳給呼叫函式後印出
請試寫一函式可回傳 加到 n 的結果 請試寫另一函式可回傳 乘到 n ( n! ) 的結果 若呼叫需放參數的 function 時不放參數會發生什麼事?
函數的參數可以提供預設值 (default argument) 可以在參數列 (parameter list) 直接將參數指派數值 Def_arg.py 4 5 6 7 8 如果只執行 PrintData() 呢? def >>> The user id: The username: John The user age: 0 The user id: The username: May The user age: 0 The user id: The username: No name The user age: 0 >>>
函數定義中也沒有限制回傳值的數量 可在 retrun 陳述中以逗號分隔回傳值 Multi_return.py 4 5 6 7 5 9 0
請試寫一 function 可同時回傳 n! 與 Σ ~n 的 function, 並改成即使呼叫時不加入引數也不會錯誤
Call_error.py 4 5 # 這行可以執行嗎? 會發生什麼事?
x, y 為 F() 函數內的區域變數 (local variable) F() 之外的地方無法存取 x, y 的值 直譯器在 F() 函數的區塊內才認得變數 x, y 離開函數直譯器便不認識這個名稱
排列組合應用 從 n 個相異物中不重覆取出 m 個之組合數 從 n 個相異物中不重覆取出 m 個之排列數
呼叫 (call) 函數時 參數必須按照順序提供, 若沒有按照順序, 就需要把參數名稱打出來, 沒有給預設值的參數必須給值 Def_arg.py 4 5 6 7 如果執行 PrintData(name= Dany ) 呢? def >>> The user id: 0 The username: John The user age: 0 The user id: The username: May The user age: 0 >>>
函數 (function) 可以有不定個數的參數 (parameter), 也就是可以在參數列 (paramenter list) 提供任意長度的參數個數 Multi_arg.py def function_name(*arguments, **keywords): #dosomething return something *arguments 就是參數識別字 (identifier) 前面加上一個星號, 當成一組序對 (tuple) **keywords 參數識別字前面加上兩個星號, 當成一組字典 (dictionary)
Multi_arg_tuple.py 4 def hello(*names): for n in names: print("hello, %s."%n) hello("tom","peter","bob","rain") Multi_arg_dict.py 4 5 def hello(**names): for n in names: print("hello",n,end=', ') print("you are",names[n],"years old") hello(john=5, Tom=0, Bob=) 就像宣告變數一般, 不得為數字
傳遞的參數內容會被 copy 到函式用來接收參數的變數中 事實上是兩個不同的變數 所以函式中改變參數數值時, 原來呼叫處的數值並不會改變 PassValue.py 4 5 6 7 8 9
函式在做引數傳遞呼叫函式的引數是容器時 會將記憶體位址傳給被呼叫函式內的引數 函式中對容器所做的改變會影響原容器 PassList.py 4 5 6 7 8 9
把容器當參數來傳遞時, 如果傳遞的只是容器的某欄位中的一個變數, 那和傳普通變數沒有什麼分別 Ex: list = [,,,4,5] func(list[0]) 如果傳的是整個容器, 傳遞的東西會是容器的位址 Ex: list = [,,,4,5] func(list)
令使用者輸入一 N 個數字的數列, 以 - 結束 並存入 list ( 不包含 -) 再試寫一個函數將此 list 傳入 並且找出此 list 中第三大的數 (sort) 後回傳印出 印出此未排序的 list ( 令容器在函式中不會改變 )
假定某班有 5 位學生, 每位學生各修 門科目 請利用二維 List 的方式儲存學生的各科成績 並設計一函式可計算一 List 之總分與平均 最後將每位學生的各科成績 總分及平均列印出來, 並找出班上最平均高分的學生
函數 (function) 中若使用 return, 函數會直接回傳數值 (value), 也隨之終止函數執行 若使用另一個關鍵字 (keyword) yield, 可使函數產生數值, 而不會結束函數執行, 這樣的函數被稱為產生器函數 (generator function) Yield.py 4 5 6 7
函數內的變數包括參數 (parameter) 都稱為區域變數 (local variable), 區域變數的使用範圍 (scope) 限於函數的區塊 (block) 內, 一旦離開該區塊範圍便由記憶體中釋放掉, 便無法繼續使用原本在區塊內的變數值, 下次呼叫該函式時再重新配置記憶體給該函式使用 另外提供一種變數可供多個函式共同使用, 變數的有效時間一直到程式結束為止, 我們將此類的變數稱為 全域變數 (Global variable)
自動變數只在它所定義的區塊內有效 只要在變數所屬的區塊結構內執行, 該變數的資料是有效而正確的 當程式執行離開了該區塊, 所有於區塊內定義的自動變數就不存在了 Local.py 4 5 6 7 8 9 x => => x x x x x x x x
全域變數的有效範圍不是區域性, 而是整體 變數定義在任何函數的外面, 可被其他函數所共用 僅限取值, 不得放在 = 號左邊, 除非宣告成 global Global_v.py 4 5 6 7 8 9 x 0 x x
程式中區域變數與全域變數的名稱相同, 當存取函式內的變數時會以區域變數為優先, 使用時最好注意, 建議全域變數最好不要和區域變數的名稱重複, 以免參用時造成混淆 Local.py 4 5 6 7 8 9 0 0 0 區域變數的名稱可以重複使用 在不同函數內被宣告的區域變數就代表是 個不同的變數
global 修改區域變數 Ex: Global_v.py 4 5 6 7 8
def outer(a): def inner(a): a += print("inner a =", a) a += inner(a) print("outer a =", a) a = 0 print("global a =", a) outer(a) print("global a =", a)
def outer(a): # 這時 inner() 裡的 a global 的 a def inner(): global a a += print("inner a =", a) a += inner() print("outer a =", a) a = 0 print("global a =", a) outer(a) print("global a =", a)
def outer(a):#inner() 裡的 a 是上一層的 a, 就是 outer() 的 a def inner(): nonlocal a a += print("inner a =", a) a += inner() print("outer a =", a) a = 0 print("global a =", a) outer(a) print("global a =", a)