Python 函式回傳值與多重回傳
簡介
在程式開發的過程中,函式(Function)不只是執行一段程式碼那麼簡單,它也是 資訊傳遞的橋樑。函式的回傳值決定了呼叫端能取得什麼結果,直接影響程式的可讀性、可測試性與維護成本。
尤其在 Python 中,回傳值的彈性相當高:不只可以回傳單一物件,還可以一次回傳多個值,甚至是 None 代表「無回傳」。掌握這些技巧,能讓你寫出更簡潔、模組化的程式,從基礎練習到實務專案都少不了。
本篇文章將以 淺顯易懂 的方式說明函式回傳值的概念、常見寫法、實作範例,並探討多重回傳的原理與應用,最後提供陷阱、最佳實踐與實務情境,幫助初學者到中級開發者快速上手。
核心概念
1. 基本回傳 (return)
函式執行到 return 陳述式時,會把緊接在其後的物件傳回給呼叫端。若沒有 return,Python 會自動回傳 None。
def square(x):
"""傳回 x 的平方"""
return x * x
result = square(5) # result 為 25
print(result)
小技巧:
return後面可以直接寫運算式,省去額外的變數。
2. 回傳 None 的意義
None 常用來表示「沒有結果」或「失敗」。在函式內部可以透過條件判斷決定是否回傳 None,讓呼叫端自行處理例外情況。
def find_user(username, users):
"""在 users(字典)中搜尋 username,找不到回傳 None"""
return users.get(username) # 若 key 不存在,dict.get 會回傳 None
user = find_user('alice', {'bob': 1, 'carol': 2})
if user is None:
print('使用者不存在')
3. 多重回傳(Tuple Packing & Unpacking)
Python 允許一次回傳多個值,背後其實是將多個物件打包成 tuple,再交給呼叫端。呼叫端可以一次解包(unpacking)取得各個值。
def stats(numbers):
"""回傳列表的最小值、最大值與平均值"""
total = sum(numbers)
count = len(numbers)
return min(numbers), max(numbers), total / count # 回傳 tuple
minimum, maximum, average = stats([3, 7, 2, 9])
print(f"最小: {minimum}, 最大: {maximum}, 平均: {average:.2f}")
重點:即使只寫一個值
return x,(注意逗號),仍會回傳單元素 tuple,避免與單一值混淆。
4. 回傳可變資料型別(list、dict、object)
回傳的物件可以是任何 Python 資料型別,甚至是自訂類別。需要注意的是 可變物件的參考傳遞,若在呼叫端修改回傳值,原始資料也會受到影響。
def get_config():
"""回傳一個設定字典,呼叫端可以直接修改"""
return {'debug': True, 'timeout': 30}
cfg = get_config()
cfg['debug'] = False # 原始字典也被改變
print(cfg)
如果不希望呼叫端改變原始資料,可以回傳 深拷貝(copy.deepcopy)或將資料轉換為不可變型別(如 tuple、frozenset)。
程式碼範例
範例 1:簡單回傳與預設值
def greet(name="使用者"):
"""若未提供 name,使用預設值"""
return f"哈囉,{name}!"
print(greet()) # 哈囉,使用者!
print(greet("小明")) # 哈囉,小明!
範例 2:回傳 None 代表錯誤
def divide(a, b):
"""除法運算,b 為 0 時回傳 None"""
if b == 0:
return None
return a / b
result = divide(10, 0)
if result is None:
print("除數不可為 0")
else:
print(result)
範例 3:多重回傳 – 資料驗證
def validate_user(username, password):
"""
回傳 (is_valid, message):
- is_valid: bool,驗證結果
- message: 錯誤或成功訊息
"""
if len(username) < 3:
return False, "使用者名稱太短"
if len(password) < 6:
return False, "密碼必須至少 6 個字元"
return True, "驗證成功"
valid, msg = validate_user("abc", "12345")
print(valid, msg) # False 使用者名稱太短
範例 4:回傳可變結構(list)
def filter_even(numbers):
"""回傳所有偶數組成的列表"""
return [n for n in numbers if n % 2 == 0]
evens = filter_even([1, 2, 3, 4, 5, 6])
print(evens) # [2, 4, 6]
範例 5:多重回傳搭配解包(星號展開)
def get_coordinates():
"""回傳 (x, y, z) 三個座標值"""
return 12.5, -7.3, 0.0
# 只取前兩個座標,剩下的用 *rest 收集
x, y, *rest = get_coordinates()
print(f"x={x}, y={y}, 其餘={rest}") # x=12.5, y=-7.3, 其餘=[0.0]
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
忘記 return |
函式只執行無回傳,呼叫端得到 None,容易產生 TypeError。 |
確認每條執行路徑都有 return,或在函式結尾加上 return None 以明確表達。 |
| 回傳可變物件導致副作用 | 呼叫端改變回傳的 list/dict,原始資料被意外修改。 | 使用 copy.deepcopy() 或回傳不可變型別(如 tuple)。 |
| 多重回傳時忘記解包 | 直接把回傳的 tuple 賦值給單一變數,導致變數是 tuple 而非各別值。 | 使用 a, b = func() 或 a, *rest = func() 正確解包。 |
| 回傳過多值,降低可讀性 | 一次回傳 5~6 個值,呼叫端難以記住每個位置的意義。 | 考慮回傳 namedtuple、dataclass 或 dict,提升可讀性。 |
回傳 None 與布林值混用 |
有時把 None 當作 False 判斷,可能隱藏錯誤。 |
明確使用 is None 來檢查 None,或使用例外(raise)表示錯誤。 |
最佳實踐
- 單一職責:每個函式只回傳與其功能直接相關的資訊,避免一次回傳過多不相關的值。
- 使用型別註解:
def func() -> Tuple[int, str]:讓 IDE 與閱讀者清楚知道回傳型別。 - 文件字串(docstring):在函式最上方說明回傳值的型別與意義,配合
help()使用。 - 盡量回傳不可變資料:若資料不需要在外部修改,使用
tuple、frozenset,減少副作用。 - 錯誤處理:對於可能失敗的情況,優先考慮拋出例外 (
raise ValueError) 而非回傳None,讓錯誤更易追蹤。
實際應用場景
| 場景 | 為什麼需要回傳值 | 範例 |
|---|---|---|
| 資料庫查詢 | 需要把查詢結果(可能是多筆資料)回傳給上層處理。 | def fetch_user(id) -> Optional[dict]: |
| 統計分析 | 同時計算多項指標(最小、最大、平均),一次回傳即可。 | def compute_stats(data) -> Tuple[float, float, float]: |
| API 回傳 | 服務端回傳 JSON 結構,呼叫端直接使用字典。 | def call_api(url) -> dict: |
| 圖形繪製 | 計算座標點後回傳多個座標值供繪圖函式使用。 | def calculate_path(...) -> List[Tuple[int, int]]: |
| 使用者驗證 | 回傳驗證結果與錯誤訊息,讓 UI 能即時顯示。 | def login(username, pwd) -> Tuple[bool, str]: |
這些情境中,正確設計回傳值的型別與結構 能讓程式碼更具可讀性、可測試性,也更容易在團隊協作時維護。
總結
- 函式的回傳值是資訊流的關鍵,決定了上層程式能取得什麼結果。
- Python 支援 單值回傳、
None、多重回傳(透過 tuple)以及 任意資料型別 的回傳,提供極大的彈性。 - 使用 型別註解、docstring、單一職責 的設計原則,能讓回傳值更易於理解與維護。
- 注意 可變物件的副作用、解包錯誤 以及 錯誤處理,避免常見陷阱。
- 在實務開發中,回傳值常用於資料庫查詢、統計分析、API 呼叫、圖形座標與驗證結果等場景,正確運用能大幅提升程式的可重用性與可測試性。
掌握了函式回傳值與多重回傳的技巧後,你就能寫出 更乾淨、更可靠 的 Python 程式,為日後的專案開發奠定堅實的基礎。祝你在程式之路上持續成長!