Maya 把同一個總價公式粘貼到四個地方,其中一份已經算錯了。函式給這個公式一個名字、一個家。訂單為空時,它應該回傳什麼?
函式是一段有名字、可以接收輸入並回傳結果的程式碼。函式讓程式更容易測試、復用和閱讀。用 def 定義函式,然後用名字呼叫它。 你還會把計算和展示分開,並在函式邊界做驗證。
定義與呼叫
定義函式只是建立它,不會立即執行。在函式名後加括號呼叫才會執行函式體。參數是定義中的名字;實參是呼叫時傳入的值。
def greet(name):
return f"你好,{name}!"
print(greet("Maya"))可復用的訊息
回傳值
return 把值送回呼叫者,並結束函式。print 只負責顯示,不會給呼叫者一個可用的結果。沒有 return 語句的函式會回傳 None。
def total(price, quantity):
return price * quantity
result = total(4.5, 2)
print(result)回傳計算結果
預設值與關鍵字參數
呼叫者省略某個參數時,會使用預設參數。帶預設值的參數必須放在沒有預設值的參數後面。函式有多個參數時,關鍵字參數可以讓呼叫更易讀。
def total(price, quantity=1):
return price * quantity
print(total(4.5))
print(total(price=4.5, quantity=3))預設值與命名參數
回傳值,而不是列印
會列印的函式不好復用;會回傳的函式可以組合、測試,再由呼叫方決定怎麼顯示。把計算和展示分開,在程式邊緣列印,不要在計算中間列印。
def line_total(qty, price):
return round(qty * price, 2)
subtotal = line_total(2, 4.5) + line_total(1, 3.0)
print(f"subtotal: {subtotal:.2f}")回傳值可以被組合
在函式邊界驗證
在參數進入函式時驗證,並拋出具體例外和有用資訊。呼叫方可以決定重試、跳過這一行還是停止。悄悄回傳 None 會隱藏失敗。
def line_total(qty, price):
if qty <= 0:
raise ValueError("qty must be positive")
if price < 0:
raise ValueError("price must be non-negative")
return round(qty * price, 2)
print(line_total(2, 4.5))
try:
line_total(0, 4.5)
except ValueError as error:
print(type(error).__name__, error)一次驗證,清楚失敗
不要使用可變預設參數
預設參數只在函式定義時求值一次。列表預設值會被所有沒有傳參的呼叫共用。正確做法是用 None 作為預設值,在函式內部新建列表。這不是風格偏好,而是防止資料在多次呼叫之間洩漏。
def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
print(add_item("latte"))
print(add_item("tea"))每次呼叫都得到新列表
本課要點
- def 定義函式,括號呼叫函式。
- return 把值送回呼叫者,print 只負責顯示。
- 預設參數讓可選參數更方便。
- 每個函式只專注做一件事。
- 回傳值可以組合;print 只是副作用。
- 當真正的預設值是可變物件時,用 None 作為預設參數。
常見錯誤
- 忘記呼叫函式,只寫了函式定義,所以函式體沒有執行。
- 呼叫者需要回傳值時,函式裡卻只用了 print。
- 把沒有預設值的參數放在有預設值的參數後面。
- 呼叫方需要結果時,函式卻只列印不回傳。
- 寫 def add(item, basket=[]),讓所有呼叫共用同一個列表。
寫一個函式,接收價格和數量並回傳總價,然後列印結果。
動手試試
改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。
練習本課
12 道題,作答後立即看到解釋。