Python

真實專案體驗:把所有技能整合進一個可以跑的小專案

模組五教你把前四個模組學到的技能,整合進一個真正可以執行的 CSV 資料整理工具:讀取、清洗、過濾、輸出報表一次到位。你會學到用 argparse 接收命令列參數、用 logging 取代 print 做正式日誌記錄,並學會寫出「AI 看得懂的完整規格書」,讓 AI 一次產出可以跑的中型專案。
真實專案體驗:把所有技能整合進一個可以跑的小專案

真實專案體驗:把所有技能整合進一個可以跑的小專案

你已經學過變數、資料結構、函式、類別與例外處理,但這些技能還沒有真正合體過。模組五要做的事,就是把它們全部放進一個看起來像樣的真實專案:一個讀取 CSV、清洗資料、輸出報表的小工具。

這也是入門篇的最後一哩路。完成這一課,你會看懂 AI 產出的 200 到 500 行專案,也會知道怎麼把需求寫成一份「AI 看得懂的規格書」,讓它一次產出可以跑的完整程式。

你將學到什麼

專案結構與進入點

看懂 main.py、config.json、src 資料夾的標準骨架,認出 if __name__ == "__main__" 這道大門。

命令列參數與設定檔

用 argparse 和 JSON 設定檔讓程式可配置,不用每次改程式碼。

用 logging 取代 print

分等級、同時輸出到終端與檔案,正式專案的日誌記錄方式。

整合實作:CSV 整理工具

讀取、清洗、過濾、輸出報表,一次用上前四個模組的技能。

給 AI 完整規格書

六要素規格書模板,讓 AI 一次產出可以跑的完整程式。

三道遞進題

讀懂、改寫、抓錯,用實戰題檢驗你是否真的把技能整合起來了。

從零件到機器:整合前四個模組

模組五要做三件事:整合前四個模組學到的技能、把一行需求升級成有結構的規格書、動手做一個 CSV 資料整理工具。完成這一課,你就有能力讀懂並精準指揮 AI 產出中型專案。

  • ① 看懂一個多檔案專案的進入點和執行流程
  • ② 用 logging 取代 print 做正式的日誌記錄
  • ③ 寫出「AI 看得懂的完整需求規格書」

5-1 專案結構與 main 進入點

一個可維護的 Python 專案有固定的慣例結構。AI 產出多個檔案的專案時,你要能看懂這個骨架。

my_project/
├── main.py          # 進入點,執行 python main.py 啟動
├── config.json      # 設定檔(不要把設定硬寫在程式裡)
├── requirements.txt # 所有第三方套件清單
├── .env             # 環境變數(API Key,不上傳 git)
├── src/             # 主要程式碼
│   ├── processor.py
│   └── utils.py
└── output/          # 輸出結果

main 進入點:if __name__ == "__main__"

# main.py
from src.processor import DataProcessor

def main():
    processor = DataProcessor()
    processor.run()

if __name__ == "__main__":
    main()
# 這行是 Python 的慣例:只有直接執行這個檔案時才跑 main()
# 其他檔案 import 這個模組時不會自動執行
Vibe Coder 觀察重點看到 if __name__ == "__main__": 這是「程式的大門」。AI 產出的每個可執行 .py 都應該有這一行,確保被其他模組 import 時不會自動執行。

5-2 命令列參數與設定檔

把參數寫死在程式裡是壞習慣,真實專案用命令列參數或設定檔讓程式可配置,不需要每次改程式碼。

import argparse

def parse_args():
    parser = argparse.ArgumentParser(description="CSV 資料整理工具")
    parser.add_argument("--input",  required=True,  help="輸入 CSV 路徑")
    parser.add_argument("--output", default="output.csv", help="輸出路徑")
    parser.add_argument("--limit",  type=int, default=100, help="最大筆數")
    return parser.parse_args()

# 使用:python main.py --input data.csv --limit 50

讀取 JSON 設定檔

import json
from pathlib import Path

def load_config(path="config.json"):
    config_path = Path(path)
    if not config_path.exists():
        return {}
    with config_path.open(encoding="utf-8") as f:
        return json.load(f)
Vibe Coder 給 AI 的設定檔提示詞「程式的所有可調整參數(路徑、閾值、API endpoint)請讀取 config.json,不要硬寫在程式碼裡。config.json 提供預設值,命令列參數可覆蓋。」

5-3 日誌記錄(logging)

logging 是 Python 標準的日誌模組,比 print 強大:可以分等級、同時輸出到終端和檔案,正式環境可關掉除錯訊息。正式專案不用 print 記錄狀態,要用 logging。

import logging

# 一次設定,整個專案通用
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.StreamHandler(),                      # 輸出到終端
        logging.FileHandler("app.log", encoding="utf-8")  # 輸出到檔案
    ]
)
logger = logging.getLogger(__name__)

# 使用五個等級
logger.debug("偵錯訊息(開發時用)")
logger.info("程式正常執行")
logger.warning("有點奇怪但不影響執行")
logger.error("發生錯誤,但程式繼續")
logger.critical("嚴重錯誤,程式可能無法繼續")
等級數值使用時機
DEBUG10開發除錯,上線關掉
INFO20正常執行記錄(預設)
WARNING30異常但不影響執行
ERROR40功能性錯誤
CRITICAL50嚴重到程式可能停止

5-4 整合實作:CSV 資料整理工具

用前四模組學到的技能,組合成一個真實工具:讀取 CSV、清洗資料、過濾、輸出報表。

讀取 CSVload_csv清洗資料clean_data過濾資料分數需≥60分輸出報表report.jsonlogging:全程記錄每一步的執行狀態與例外
CSV 整理工具的資料流:讀取、清洗、過濾、輸出報表,logging 在旁全程記錄。
import csv, json, logging
from pathlib import Path

logging.basicConfig(level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

def load_csv(path: str) -> list:
    """讀取 CSV,回傳 list of dict。"""
    try:
        with open(path, encoding="utf-8") as f:
            return list(csv.DictReader(f))
    except FileNotFoundError:
        logger.error(f"找不到檔案:{path}")
        return []

def clean_data(records: list) -> list:
    """去除空白、過濾缺少必要欄位的列。"""
    cleaned = []
    for r in records:
        name = r.get("name", "").strip()
        score = r.get("score", "").strip()
        if not name or not score:
            logger.warning(f"跳過不完整列:{r}")
            continue
        try:
            cleaned.append({"name": name, "score": int(score)})
        except ValueError:
            logger.warning(f"分數格式錯誤:{score}")
    return cleaned

generate_report 與 main 進入點

def generate_report(records: list) -> dict:
    """計算統計報表。"""
    scores = [r["score"] for r in records]
    passed = [r for r in records if r["score"] >= 60]
    return {
        "total":   len(records),
        "passed":  len(passed),
        "average": sum(scores) / len(scores) if scores else 0,
        "highest": max(scores) if scores else 0,
    }

if __name__ == "__main__":
    data   = load_csv("scores.csv")
    clean  = clean_data(data)
    report = generate_report(clean)
    logger.info(f"報表:{report}")
Vibe Coder 觀察重點:這段程式用到了哪些技能
  • 模組二:f-string、條件判斷、函式、型別轉換
  • 模組三:list of dict、推導式、.get() 安全取值
  • 模組四:try/except 分層、with open(encoding="utf-8")
  • 模組五:logging、__name__ == "__main__"、型別提示

5-5 給 AI 下完整專案指令

Vibe Coder 的核心技能不是寫程式,是寫出 AI 看得懂的完整需求規格書。以下是一份可直接給 AI 的規格書模板。

請用 Python 3.10+ 寫一個 CSV 資料整理工具,規格如下:

【功能】
- 讀取指定路徑的 CSV 檔案(utf-8 編碼)
- 清洗:去除空白,過濾缺少 name 或 score 欄位的列
- 過濾:只保留 score >= 60 的列
- 輸出:產生 report.json,包含 total/passed/average/highest

【架構要求】
- 拆成函式:load_csv、clean_data、filter_data、generate_report
- 用 logging 而非 print(INFO 等級,同時輸出終端和 app.log)
- 所有 open 必須用 with 且指定 encoding="utf-8"
- 所有例外必須有具體的 except 類型和錯誤訊息,不用裸露 except
- 進入點用 if __name__ == "__main__",接受 --input 和 --output 命令列參數

【輸出格式】
- 每個函式加 docstring(一行說明)和中文行內註解
- requirements.txt 列出所有第三方套件(如果有)
Vibe Coder 規格書六要素① 功能清單(做什麼)② 輸入格式(吃什麼)③ 輸出格式(吐什麼)④ 架構要求(怎麼組織)⑤ 防護要求(例外、型別、編碼)⑥ 文件要求(docstring、註解)

三道遞進題:讀懂、改寫、抓錯

入門篇的壓軸作業,分三關:讀懂多個函式協同運作的完整流程、把 print 和硬寫參數改寫成正式寫法、在整合型程式裡抓出架構與例外處理混在一起的 bug。

題目一:讀懂(基礎)

def process(path, min_score=60):
    with open(path, encoding="utf-8") as f:
        lines = f.readlines()
    results = []
    for line in lines[1:]:           # 跳過表頭
        name, score = line.strip().split(",")
        if int(score) >= min_score:
            results.append({"name": name, "score": int(score)})
    return sorted(results, key=lambda x: x["score"], reverse=True)

print(process("scores.csv"))

任務:逐行說明,解釋 lines[1:]split(",")lambda 各自的作用。

答案拆解
  1. lines[1:]:切片跳過第一行(表頭),從第二行開始處理資料。
  2. line.strip().split(",") :去空白後用逗號切割,拆成 [name, score] 兩個元素,再用 unpack 分別指定給 name 和 score。
  3. lambda x: x["score"]:匿名函式,告訴 sorted 用每個 dict 的 score 值排序;reverse=True 是由大到小。

題目二:改寫(進階)

從能跑到能維護模組五的改寫目標不只是讓程式跑起來,而是讓程式可維護、可配置、可監控。加上 logging、設定檔、命令列參數,是讓 Vibe Coder 產出物從玩具等級升級到工具等級的關鍵。

用以下提示詞請 AI 升級題目一的程式:

請改進上面的 process 函式,升級成生產等級:
1. 用 argparse 接收 --input(必填)和 --min-score(預設 60)
2. 把 print 改成 logging(INFO 等級,輸出到終端和 process.log)
3. 加上例外處理:
   - FileNotFoundError:記錄錯誤並回傳空 list
   - ValueError(split 失敗或 int 轉換失敗):記錄警告、跳過該列
4. 輸出結果寫入 report.json(UTF-8)
5. 用 if __name__ == "__main__" 包住進入點
每行加中文註解,加上 docstring。
答案拆解
  • argparse:讓程式從命令列接收參數,不需要改程式碼就能換輸入檔和閾值。
  • logging:讓你有執行記錄(寫到 .log 檔),上線後除錯靠它而不是重跑。
  • 兩種例外分開處理:FileNotFoundError 是致命錯誤(回傳空);ValueError 是資料問題(跳過繼續)。

題目三:抓錯(高階)

整合型專案的 bug 最難找,每個函式看起來都沒問題,但組合在一起就出錯。這道題考的是你追蹤跨函式資料流的能力。

import csv, logging

log = logging.getLogger()

def load_and_process(path):
    records = []
    try:
        f = open(path)           # 問題一
        reader = csv.DictReader(f)
        for row in reader:
            score = int(row["score"])  # 問題二
            records.append(row)
        f.close()
    except Exception:          # 問題三
        log.error("發生錯誤")    # 問題四
    return records

任務:找出四個標注的問題,說明危險原因,並寫出修正提示詞。

問題說明
問題一沒有 with 且沒有 encoding。例外發生時 f.close() 不會執行;沒有 encoding 中文會亂碼。
問題二row["score"] 用中括號取值,key 不存在會拋 KeyError;int() 轉換失敗會拋 ValueError。兩種都沒有個別處理。
問題三裸露 except Exception(沒有 as e),捕捉到例外但無法知道具體錯誤是什麼。
問題四logging 沒有設定(沒有呼叫 basicConfig),log.error() 可能沒有任何輸出。

術語速查表

術語說明
if __name__ == "__main__"Python 的進入點守衛,只有直接執行這個檔案時為 True,被 import 時為 False。
requirements.txt列出所有第三方套件的清單,pip install -r requirements.txt 一次安裝全部。
argparse標準庫的命令列參數解析模組,讓程式接受 --input 等參數。
logging標準庫的日誌記錄模組,取代 print,可分等級、寫檔、格式化。
logger = logging.getLogger(__name__) 建立以模組名稱命名的 logger,方便追蹤訊息來源。
pathlib.Path現代路徑操作(Python 3.4 以上),比 os.path 更直觀。
csv.DictReader讀取 CSV 並自動把每列轉成 dict(以表頭為 key)。
lambda匿名函式,lambda x: x["score"] 等於一個只有 return 的短函式。
sorted(lst, key=func) 依指定函式的回傳值排序,reverse=True 為降序。
.env 檔案存放環境變數(API Key 等敏感資訊),不上傳 git,用 python-dotenv 讀取。
docstring函式或類別定義後的第一個字串,說明功能、參數和回傳值。
type hint(型別提示)def f(x: int) -> str,說明參數和回傳型別,不影響執行但增加可讀性。

重點整理:入門篇五模組總回顧

模組核心技能
模組一|環境與心態Python 安裝、AI Vibe Coder 定位、安全陷阱
模組二|語言核心型別、字串、條件、迴圈、函式
模組三|資料結構list、dict、set、tuple、推導式
模組四|程式架構import、例外處理、class、檔案讀寫
模組五|真實專案專案結構、logging、argparse、規格書寫法
入門篇完成!你現在能做什麼?讀懂 AI 產出的 200 到 500 行專案。精準用六要素規格書下指令。找出型別、架構、資料流的常見 bug。

模組五完成清單

  • □ 看懂多檔案專案的進入點和執行流程
  • □ 知道 if __name__ == "__main__" 的作用
  • □ 能用 argparse 讓程式接受命令列參數
  • □ 能用 logging 取代 print,設定等級和輸出目標
  • □ 完成作業題目一:說明 lambda、切片、split 的作用
  • □ 完成作業題目二:用六要素規格書請 AI 升級程式
  • □ 完成作業題目三:找出 with、encoding、裸 except、logging 未設定四個問題

延伸學習

把這篇文章分享給需要的人FacebookLINEThreadsX

常見問答

if __name__ == "__main__" 是做什麼用的?
這是 Python 的進入點守衛,只有直接執行這個檔案時才會是 True 並執行裡面的程式;被其他檔案 import 時則不會自動執行,避免模組被引用時跑出不該執行的程式碼。
為什麼正式專案要用 logging 而不是 print?
logging 可以分等級,從 DEBUG 到 CRITICAL,也能同時輸出到終端和檔案;上線後可以只保留 INFO 以上的訊息,不像 print 一律印出、無法分級也無法關閉。
給 AI 完整規格書要包含哪六個要素?
功能清單、輸入格式、輸出格式、架構要求、防護要求(例外、型別、編碼)、文件要求(docstring、註解),六項寫齊,AI 才能一次產出可用的完整程式。
argparse 和設定檔要怎麼分工?
設定檔負責提供預設值,命令列參數用來覆蓋設定檔,讓同一支程式不用改程式碼就能換輸入檔、換閾值,兩者搭配才是真正的可配置。