2026年8月31日 星期一

Python一下:從單一程式走向模組、套件與可執行腳本

《Python一下:從風土資料到智慧生活》第 11 篇

從單一程式走向模組、套件與可執行腳本

把智慧養殖巡查程式拆成可重用、可測試,也能由現場人員直接執行的工具。

CH7 模組與套件importUSR 場域程式
學習目標
完成本篇後,你能說明模組、套件與腳本的差異;使用不同形式的 import;以 __name__ == "__main__" 區分匯入與執行;並把智慧養殖巡查程式整理成小型專案。

一、程式為什麼要「分家」?

初學時,把輸入、計算與輸出寫在同一個檔案很方便。但當程式開始讀取多座養殖場資料、判斷水質、輸出巡查報告時,單一檔案會愈來愈難修改。合理拆分後,判斷規則可以重複使用,主程式也能專注描述工作流程。

名稱在 Python 中的意義本篇案例
模組 module一個 .py 程式檔water_quality.py
套件 package收納相關模組的資料夾shuijing_monitor/
腳本 script由命令列或編輯器直接執行的程式run_patrol.py
場域安全提醒:教學範例中的溫度、酸鹼值及警示範圍只是示意。實際養殖管理須依物種、成長階段、設備校正結果及養殖戶經驗共同設定,不可直接把範例數值當成操作標準。

二、先把判斷函式做成模組

建立 water_quality.py。模組只負責水質資料的判斷與摘要,不在匯入時向使用者詢問資料。

"""水井村智慧養殖:水質判斷工具。"""

TEMPERATURE_RANGE = (24.0, 30.0)
PH_RANGE = (6.5, 8.5)


def in_range(value, safe_range):
    """判斷數值是否落在含端點的安全範圍。"""
    minimum, maximum = safe_range
    return minimum <= value <= maximum


def check_water(temperature, ph):
    """回傳水質檢查結果串列;空串列表示未發現異常。"""
    alerts = []
    if not in_range(temperature, TEMPERATURE_RANGE):
        alerts.append(f"水溫需確認:{temperature}°C")
    if not in_range(ph, PH_RANGE):
        alerts.append(f"pH 值需確認:{ph}")
    return alerts


def format_report(site_name, temperature, ph):
    """產生單一場域的文字報告。"""
    alerts = check_water(temperature, ph)
    status = "正常" if not alerts else ";".join(alerts)
    return f"{site_name}|水溫 {temperature}°C|pH {ph}|{status}"

三、用 import 重複使用模組

patrol_demo.pywater_quality.py 放在同一資料夾,便能匯入模組。

import water_quality

report = water_quality.format_report("示範池 A", 27.2, 7.4)
print(report)

使用「模組名稱+點」能清楚看出函式來自哪裡。另有兩種常見寫法:

from water_quality import format_report

print(format_report("示範池 B", 31.1, 7.8))
import water_quality as wq

print(wq.format_report("示範池 C", 25.6, 6.2))
建議:模組名稱較長時可使用清楚的別名;避免 from 模組 import *,因為名稱來源不明,也可能覆蓋原有變數或函式。

四、認識 __name__ 與程式入口

Python 直接執行檔案時,該檔案的 __name__"__main__";被其他程式匯入時,則是模組名稱。利用這項規則,可讓測試示範只在直接執行時出現。

def main():
    print(format_report("模組自我測試池", 27.0, 7.2))


if __name__ == "__main__":
    main()

將這段放在 water_quality.py 最後。直接執行模組會看到測試報告;其他程式只匯入函式時,不會自動印出內容。

五、從模組組成套件

當功能再增加,可把相關模組放入同一套件。建議專案結構如下:

shuijing_project/ ├─ run_patrol.py ├─ data/ │ └─ sites.csv └─ shuijing_monitor/ ├─ __init__.py ├─ water_quality.py └─ report.py

__init__.py 可保持空白,也能公開最常使用的函式:

"""水井村智慧養殖巡查工具套件。"""

from .water_quality import check_water, format_report

__all__ = ["check_water", "format_report"]

其中的點代表「目前套件」。設定 __all__ 是在說明套件預計提供哪些名稱,但不等同存取權限或安全機制。

六、套件內的相對匯入

新增 report.py,把多筆場域資料整理成巡查報告:

from .water_quality import format_report


def build_patrol_report(records):
    """將場域紀錄轉成多行巡查報告。"""
    lines = ["水井村智慧養殖巡查報告", "=" * 24]
    for record in records:
        lines.append(
            format_report(
                record["場域"],
                record["水溫"],
                record["pH"],
            )
        )
    return "\n".join(lines)

七、完成可直接執行的巡查腳本

根目錄的 run_patrol.py 是整個專案入口。它準備資料、呼叫套件函式並顯示結果。

from shuijing_monitor.report import build_patrol_report


def main():
    records = [
        {"場域": "示範池 A", "水溫": 27.2, "pH": 7.4},
        {"場域": "示範池 B", "水溫": 31.1, "pH": 7.8},
        {"場域": "示範池 C", "水溫": 25.6, "pH": 6.2},
    ]
    print(build_patrol_report(records))


if __name__ == "__main__":
    main()

在終端機切換到 shuijing_project 後執行:

python run_patrol.py

八、標準函式庫與第三方套件不同

來源例子是否另行安裝
自己撰寫shuijing_monitor同一專案中通常不需要
Python 標準函式庫csvjsonpathlib隨 Python 提供
第三方套件requestspandas通常使用 pip 安裝

安裝第三方套件時,建議在專案的虛擬環境中執行,例如:

python -m pip install requests

使用 python -m pip 能較明確地讓 pip 對應到目前使用的 Python。

九、匯入時 Python 去哪裡找?

Python 會從目前程式所在位置、環境設定與已安裝套件路徑中尋找模組。遇到 ModuleNotFoundError 時,先檢查:

  1. 檔名與匯入名稱是否一致,大小寫是否正確。
  2. 是否從專案根目錄執行主程式。
  3. 模組檔名是否誤用 csv.pyjson.py 等標準模組名稱。
  4. Thonny、終端機與 Colab 是否使用不同的 Python 環境。

十、常見錯誤與修正

現象原因修正
一 import 就開始詢問輸入互動程式寫在模組最外層放入 main() 與入口判斷
ModuleNotFoundError執行位置、檔名或環境錯誤由專案根目錄執行並確認解譯器
AttributeError函式名稱寫錯或循環匯入確認公開名稱並重新分配模組責任
同一段程式重複多份沒有抽成共同模組把計算規則集中,其他程式只匯入
匯入自己的 csv.py 出錯檔名遮蔽標準函式庫重新命名並清除舊快取

十一、USR 實作挑戰

挑戰 A|拆分責任
把巡查程式分成「感測資料驗證」、「異常判斷」與「報告輸出」三個模組,為每個模組寫一句用途說明。
挑戰 B|保留地方決策
把警示範圍移到設定模組,但不要自行假設真實數值;以註解標示「須由養殖戶與專業人員確認」。
挑戰 C|多人協作
由三位同學分別維護資料、判斷與報告模組,最後以主腳本整合,記錄匯入介面曾發生的修改。

十二、與生成式 AI 協作

請擔任 Python 專案重構助教。
請檢查我提供的智慧養殖程式,建議如何拆成模組、套件與主腳本。
要求:
1. 每個模組只負責一類工作;
2. 匯入時不能自動執行 input 或列印;
3. 主程式使用 if __name__ == "__main__";
4. 不要自行設定真實養殖安全門檻;
5. 說明每項調整的理由,再提供檔案樹與程式碼。
本篇小結
模組讓函式可以重用,套件讓多個模組形成清楚的功能群組,腳本則提供可直接執行的入口。良好的拆分不以檔案數量為目標,而是讓每個檔案的責任容易說明、測試與修改。

沒有留言:

張貼留言