Python
真實專案體驗:把所有技能整合進一個可以跑的小專案
真實專案體驗:把所有技能整合進一個可以跑的小專案
你已經學過變數、資料結構、函式、類別與例外處理,但這些技能還沒有真正合體過。模組五要做的事,就是把它們全部放進一個看起來像樣的真實專案:一個讀取 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 這個模組時不會自動執行
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)
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("嚴重錯誤,程式可能無法繼續")
| 等級 | 數值 | 使用時機 |
|---|---|---|
DEBUG | 10 | 開發除錯,上線關掉 |
INFO | 20 | 正常執行記錄(預設) |
WARNING | 30 | 異常但不影響執行 |
ERROR | 40 | 功能性錯誤 |
CRITICAL | 50 | 嚴重到程式可能停止 |
5-4 整合實作:CSV 資料整理工具
用前四模組學到的技能,組合成一個真實工具:讀取 CSV、清洗資料、過濾、輸出報表。
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}")
- 模組二: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 列出所有第三方套件(如果有)
三道遞進題:讀懂、改寫、抓錯
入門篇的壓軸作業,分三關:讀懂多個函式協同運作的完整流程、把 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 各自的作用。
lines[1:]:切片跳過第一行(表頭),從第二行開始處理資料。line.strip().split(","):去空白後用逗號切割,拆成[name, score]兩個元素,再用 unpack 分別指定給 name 和 score。lambda x: x["score"]:匿名函式,告訴 sorted 用每個 dict 的 score 值排序;reverse=True是由大到小。
題目二:改寫(進階)
用以下提示詞請 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、規格書寫法 |
模組五完成清單
- □ 看懂多檔案專案的進入點和執行流程
- □ 知道
if __name__ == "__main__"的作用 - □ 能用 argparse 讓程式接受命令列參數
- □ 能用 logging 取代 print,設定等級和輸出目標
- □ 完成作業題目一:說明 lambda、切片、split 的作用
- □ 完成作業題目二:用六要素規格書請 AI 升級程式
- □ 完成作業題目三:找出 with、encoding、裸 except、logging 未設定四個問題
延伸學習
HE201|Harness Engineering System Design(6 小時)
六小時的實作課:從 Blueprint 走到可以跑的規格,再用 No-code、n8n 低程式碼與程式碼三條路各做一次同一個 harness,最後處理可靠度——重試、錯誤處理、人工覆核。7 章 54 課,含常見坑與排錯、Capstone 實作,附學員講義 PDF。
NT$ 5,999
做出你的第一個 Skill
一場快閃直播的完整重製。從搞懂 Skill 的五個層級開始,帶你把一件你每天在做的重複工作,寫成一支 AI 真的會照做的 Skill ── 命名、description、輸入拆解、Workflow 訪談、Output 與 Checks,最後組成一份能通過格式檢查的 SKILL.md。
NT$ 999

