首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Python 函數設計核心原則:高內聚、低耦合、可維護的實戰指南

     編輯:更多程式設計知識

函數是程式碼組織的基本單元,良好的函數設計直接決定專案的可讀性、可測試性與維護成本。本文整理 Python 函數設計的三大核心維度——聚合性(Cohesion)、大小(Size)、耦合性(Coupling),並提供具體程式碼範例與效能實測,幫助開發者建立專業級的函數設計習慣。

一、聚合性:每個函數只做一件事

原則:函數應專注於單一職責,輸入明確、輸出可預期、副作用最小化。

反例:大雜燴函數

def process_order(user_id, items, payment_info, shipping_addr):
    # 驗證用戶
    # 計算價格
    # 處理付款
    # 扣減庫存
    # 發送確認信
    # 記錄日誌
    # 產生報表
    pass  # 200+ 行程式碼

正例:職責拆解

def validate_user(user_id): ...
def calculate_total(items): ...
def charge_payment(payment_info, amount): ...
def reserve_inventory(items): ...
def send_confirmation(email, order_id): ...
def log_transaction(order_id, details): ...

def process_order(user_id, items, payment_info, shipping_addr):
    validate_user(user_id)
    total = calculate_total(items)
    charge_payment(payment_info, total)
    reserve_inventory(items)
    order_id = create_order_record(...)
    send_confirmation(get_user_email(user_id), order_id)
    log_transaction(order_id, {"total": total, "items": items})
    return order_id

✅ 優點:各函數可獨立測試、複用、修改,且主流程一目瞭然。

二、大小:保持簡短、避免深層巢狀

經驗法則:

  • 函數長度 不超過一個螢幕(約 50-80 行)
  • 巢狀縮排 不超過 3 層(超過即考慮拆分)
  • 區域變數 不超過 5-7 個

巢狀過深的重構技巧

# ❌ 巢狀 4 層
def analyze(data):
    if data:
        for item in data:
            if item.valid:
                for sub in item.sub_items:
                    if sub.flag:
                        process(sub)

# ✅ 提早回傳 + 拆分
def analyze(data):
    if not data: return
    for item in data:
        process_valid_item(item)

def process_valid_item(item):
    if not item.valid: return
    for sub in item.sub_items:
        process_sub_item(sub)

def process_sub_item(sub):
    if sub.flag:
        process(sub)

三、耦合性:參數傳入、return 輸出、慎用全域狀態

1. 參數與回傳值:明確的介面契約

# ✅ 良好:輸入輸出皆明確
def calculate_discount(price: float, member_level: str) -> float:
    rates = {"gold": 0.2, "silver": 0.1, "bronze": 0.05}
    return price * (1 - rates.get(member_level, 0))

# ❌ 差:依賴全域變數
DISCOUNT_RATES = {"gold": 0.2, "silver": 0.1}
def calculate_discount_bad(price):
    return price * (1 - DISCOUNT_RATES.get(current_user.level, 0))

2. 全域變數的效能與維護代價

Python 變數查找順序:Local → Enclosing → Global → Built-in (LEGB)。區域變數查找最快,全域變數較慢。

實測:區域 vs 全域變數存取速度

import timeit

# 全域變數版本
GLOBAL_A = 5
def global_version():
    res = 0
    for i in range(10_000_000):
        res = GLOBAL_A + i
    return res

# 區域變數版本
def local_version():
    a = 5
    res = 0
    for i in range(10_000_000):
        res = a + i
    return res

print("Global:", timeit.timeit(global_version, number=1))  # 約 3.7 秒
print("Local:", timeit.timeit(local_version, number=1))    # 約 1.2 秒

📊 結果:區域變數快 3 倍以上,且避免了全域狀態造成的副作用與除錯困擾。

3. 避免修改可變參數(列表、字典)

# ❌ 危險:呼叫端列表被竄改
def add_item_bad(lst, item):
    lst.append(item)

# ✅ 安全:建立副本或回傳新列表
def add_item_good(lst, item):
    new_lst = lst.copy()  # 或 lst[:]
    new_lst.append(item)
    return new_lst

# 或使用不可變資料結構
from dataclasses import dataclass
@dataclass(frozen=True)
class Order:
    items: tuple

4. 跨模組變數存取:提供存取函式而非直接修改

# a.py
PI = 3.14
def set_pi(new_val):
    global PI
    PI = new_val
    return PI

# b.py
import a
my_pi = a.set_pi(3.14159)  # 明確意圖,不直接改 a.PI
print(my_pi, a.PI)

四、綜合檢核清單

檢核項目標準
單一職責函數名稱能精確描述其行為,無「且」、「或」
長度≤ 80 行,巢狀 ≤ 3 層
參數≤ 5 個,優先使用關鍵字參數與型別標註
回傳單一回傳類型,避免 None 與實值混用
副作用無修改全域/外部狀態,或在文件字串明確宣告
可測試無外部依賴,或可透過參數注入 Mock 物件

結語

「簡單並不代表容易」,好的函數設計需要刻意練習與持續重構。遵循高內聚、低耦合、單一職責三大原則,配合型別提示、單元測試與程式碼審查,能讓 Python 專案在規模增長時依然保持清晰、穩定且易於擴展。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved