跳到主要內容

Web Day 44 專案:文件與交接

Web Day 44 專案:文件與交接

執行需求:CPU 可跑。Stack、監控、備份、壓測都做完了,今天要把這套預約管理系統變成「可以被別人接手」的狀態。今天要做四件事:第一,寫一份 README.md(開發者上手指南、安裝指令、常用操作);第二,寫一份 runbook.md(事件處置手冊:磁碟滿、PostgreSQL 沒起來、API 5xx 飆升時的 step-by-step 復原流程);第三,整理一份 OpenAPI 規格摘要(從 FastAPI 0.116 的 /openapi.json 自動生成);第四,把 Day 40 的驗收清單(acceptance checklist)升級為正式上線文件,列為 PR 模板的一部分。所有文件都用 Markdown 寫,UTF-8 編碼,繁體中文(術語沿用 README 的台灣用語對照表);資料仍是虛構示範。今天是 Day 45 系列總結前的倒數第二天,把整套 stack 的可維運性做最後一次打磨。

引言

「寫文件」是工程師最常拖延的工作,原因是「現在沒時間」與「以後再寫」。但真正出事的時候,文件就是工程師最重要的武器:一份結構完整的 runbook 能讓接手的人凌晨三點不必打電話給原作者就能復原系統;一份更新過的 README 能讓新人第一天就上手。這些文件不是「bonus」,而是 production 系統的基本配備。

貫穿專案的預約管理系統是小型服務業線上預約平台(情境涵蓋攝影棚、健身教練、諮詢工作室,所有資料都是虛構示範)。經過 Day 35–43,我們已經有了:可跑的 stack(Docker Compose v2、PostgreSQL 17、FastAPI 0.116、Caddy 2.8);可監控(/metrics、JSON log);可備份(每日 pg_dump + 還原演練);可壓力測試(locust + 純 Python);可驗收(8 支 E2E + 驗收清單)。這些成果沒有文件,就只是「在原作者電腦裡跑得動」;有了文件,才是「可以被別人接手」的系統。

今天的內容分四段:第一段說明文件化策略(哪些文件、給誰看、如何維護);第二段寫 README.md 與 RUNBOOK.md 的範本;第三段用 Python 腳本從 /openapi.json 自動產生 API 規格摘要;第四段把 Day 40 的驗收清單升級為正式上線清單與 PR 模板。讀完這篇你會了解:為什麼寫文件是「為未來的我」投資、runbook 與 README 的本質差別、FastAPI 自動 OpenAPI 的優勢、怎麼讓驗收清單變成 commit-friendly 格式。

原理解念:README、runbook、API 規格、驗收清單

README 與 runbook 是兩種本質不同的文件:README 是「正常情況下」,給第一次接觸這個專案的開發者讀,回答「這是什麼」、「怎麼跑起來」、「怎麼測試」、「怎麼貢獻」。runbook 是「不正常情況下」,給值班的工程師在事件發生時讀,回答「症狀是什麼」、「原因可能是什麼」、「要怎麼處理」、「處理完要記什麼」。前者是 onboarding,後者是 incident response。兩者不能合併,因為讀者的心智模式不同。

API 規格摘要的目的是「不看程式碼也能對齊合約」。FastAPI 0.116 內建的 /openapi.json 是 JSON Schema 標準,包含了所有路由、請求參數、回應格式。我們可以再加一層 Markdown 摘要(路徑、方法、用途、auth 需求),幫助前端、後端、PM 三種角色快速對齊。這比寫死 docs/API.md 維護成本低:摘要從 OpenAPI 自動生成,永遠跟程式碼同步。

驗收清單(acceptance checklist)是寫在 PR 模板裡、人手一份要逐項勾的東西。它把「上線必須做的事」變成可重現的流程。Day 40 我們示範了它的雛型,今天把它升級成更完整的版本,包含開發者自查、DBA 簽核、SRE 簽核三個角色。這不是為「怕有人忘記」而設計,而是為「用最低的成本攔截最多的錯誤」而設計。

完整實作:README、RUNBOOK、API 摘要、驗收清單

先寫 README.md。我們的 README 採標準結構:標題、一句話描述、快速開始、開發流程、測試、部署、版本、授權:

# 對應的 README.md(純文字示範;以下內容是實際 repo 的 README)
README = """# 預約管理系統(booking-system)

小型服務業線上預約平台後端 API。情境涵蓋攝影棚、健身教練、諮詢工作室;所有資料皆為虛構示範。

## 技術棧
- Python 3.13、FastAPI 0.116、SQLModel 0.0.24、SQLAlchemy 2.0.41、Pydantic 2.11
- PostgreSQL 17、Caddy 2.8、HTMX 2.0、uv 0.7
- Docker Compose v2、pytest 8.4、httpx 0.28、Alembic 1.16

## 快速開始
1. 複製環境變數範本:\`cp .env.example .env\`
2. 啟動 stack:\`docker compose up -d\`
3. 跑 migrations:\`docker compose exec api alembic upgrade head\`
4. 開瀏覽器:[http://localhost/admin/dashboard](http://localhost/admin/dashboard)
   預設 admin 帳號:admin@example.com / admin-pass

## 開發流程
\`\`\`bash
uv sync                  # 安裝依賴
uv run pytest -v         # 跑測試
uv run ruff check        # linter
uv run alembic upgrade head
uv run uvicorn booking_system.main:app --reload
\`\`\`

## 測試
- \`tests/test_e2e.py\`:8 支核心 API 端對端測試
- \`tests/test_perf_health.py\`:健康檢查 P95 < 50ms smoke
- \`tests/test_migration.py\`:Alembic upgrade head 驗證
- \`tests/test_admin_dashboard.py\`:HTMX 後台互動測試

## 部署
- 開發用 docker compose up -d
- staging / production 建議升級為 Kubernetes 或 AWS ECS
- 細節請見 RUNBOOK.md

## 文件
- \`docs/API.md\`:API 路由摘要(從 /openapi.json 自動生成)
- \`docs/RUNBOOK.md\`:事件處置手冊
- \`docs/acceptance.md\`:上線驗收清單(PR 模板的一部分)

## 授權
MIT License(示範專案)。
"""
print(README.strip())

這個 README 把「快速開始」放最前面(每個 README 都該如此)、再放開發流程、測試、部署、文件、授權。專案名、版本、授權這三樣務必放,這是 GitHub 顯示專案摘要時的關鍵資訊。

接下來是 RUNBOOK.md:

RUNBOOK = """# RUNBOOK — 預約管理系統

> 事件處置手冊。當你看到告警或接到客戶投訴,第一件事是查這份文件。

## 1. 健康檢查失敗(/health 回 503 或逾時)
**症狀**:Prometheus 告警「up == 0」超過 1 分鐘;K8s liveness probe 失敗。

**處理**:
1. SSH 進主機,確認 container 還在:\`docker compose ps\`
2. 查看 container log:\`docker compose logs --tail=200 api\`
3. 若是 process crash,重啟:\`docker compose restart api\`
4. 若是 DB 連不上,先確認 db container:\`docker compose exec db pg_isready -U booking\`
5. 重啟後跑 smoke:\`curl -s http://localhost/health\`

## 2. API 5xx 比率飆升(>1% 連續 5 分鐘)
**症狀**:\`booking_errors_total\` 上升;客戶回報操作失敗。

**處理**:
1. 看 Grafana「過去 1 小時 P95」是哪條 endpoint 出包
2. 查 log:\`docker compose logs api | grep -i error | tail -50\`
3. 若全是 DB 錯誤,先查 \`pg_stat_activity\` 看是否有 long query:\`docker compose exec db psql -U booking -c 'SELECT pid, state, query FROM pg_stat_activity;'\`
4. 若 DB 沒事、API 才有事,看 \`/metrics\` 找哪個 path 爆量
5. 必要時啟動「kill switch」:\`docker compose scale api=0\` 然後 \`=1\` 把損面降到最小

## 3. PostgreSQL 磁碟滿
**症狀**:\`pg_dump\` 失敗;DB 寫入報 disk full。

**處理**:
1. SSH 進主機,\`df -h\` 看哪個分割區滿了
2. 若 backup volume 滿,先 prune:\`find /var/backups/booking -mtime +14 -delete\`
3. 若 data volume 滿,看 audit_logs:\`SELECT COUNT(*) FROM audit_logs WHERE created_at < NOW() - INTERVAL '90 days';\`,彙整歸檔或刪除
4. 清完後 \`docker compose exec db vacuumdb -U booking -d booking\`,釋放空間
5. 預防:把 archive 寫進 \`docs/RUNBOOK.md\` 的「每月歸檔」段落

## 4. 通知(simulated)沒寄出
**症狀**:客戶反映沒收到確認信;\`notification.sent\` log 沒新增。

**處理**:
1. 看 Notification 表:\`SELECT id, status, attempt_count, last_error FROM notifications WHERE status != 'sent' ORDER BY created_at DESC LIMIT 20;\`
2. 若全是 queued 沒送出,看 APScheduler 還活著:\`docker compose logs api | grep scheduler\`
3. 必要時 \`docker compose exec api uv run python -c 'from booking_system.scheduler import send_upcoming_reminders; import asyncio; asyncio.run(send_upcoming_reminders())'\`

## 5. 還原演練(disaster recovery)
**症狀**:磁碟損壞、database 損毀、需要從備份還原。

**處理**:
1. 找最新備份:\`ls -t /var/backups/booking/booking-*.sql.gz | head -1\`
2. 還原到臨時 DB:\`python scripts/restore_drill.py <備份檔> postgresql://booking:booking-dev@localhost:5432/booking-drill\`
3. 確認資料完整:\`psql -d booking-drill -c 'SELECT COUNT(*) FROM bookings;'\`
4. 切換 DNS 指向臨時 DB:\`docker compose exec caddy caddy reload\`
5. 修好正式 DB 後再切回
"""
print(RUNBOOK.strip())

這個 runbook 涵蓋五種常見事件:健康檢查失敗、5xx 飆升、磁碟滿、通知沒寄出、災難還原。每個事件包含「症狀 + 處理」。處理步驟都附具體指令,讓值班工程師照著打。我們刻意把每個場景切成 5 步以內,避免手忙腳亂時找不到下一行。

API 規格摘要自動生成器(從 FastAPI 的 /openapi.json 抽出):

# scripts/docs_gen_api_summary.py
# 從 /openapi.json 抽出每條路由的 method、path、auth、回應,寫成 Markdown
import json
import sys
from urllib.request import urlopen


def fetch_schema(base_url: str) -> dict:
    return json.loads(urlopen(f"{base_url}/openapi.json", timeout=5).read())


def render_markdown(schema: dict) -> str:
    lines = [
        f"# API 規格摘要(自動從 {schema.get('info', {}).get('title', '')} 生成)",
        "",
        f"version: {schema.get('info', {}).get('version', 'unknown')}",
        "",
        "## 路由",
        "",
    ]
    for path, methods in sorted(schema["paths"].items()):
        for method, op in methods.items():
            if method.upper() not in {"GET", "POST", "PUT", "PATCH", "DELETE"}:
                continue
            tag = (op.get("tags") or [""])[0]
            summary = op.get("summary") or op.get("description") or ""
            sec = [r for r in op.get("responses", {}) if r.startswith("2")]
            lines.append(f"### {method.upper()} {path}")
            lines.append(f"- 所屬群組:{tag}")
            lines.append(f"- 用途:{summary}")
            if sec:
                lines.append(f"- 成功回應:{', '.join(sec)}")
            lines.append("")
    return "\n".join(lines) + "\n"


if __name__ == "__main__":
    base = sys.argv[1] if len(sys.argv) > 1 else "http://localhost"
    out = sys.argv[2] if len(sys.argv) > 2 else "docs/API.md"
    schema = fetch_schema(base)
    Path = __import__("pathlib").Path
    Path(out).write_text(render_markdown(schema), encoding="utf-8")
    print(f"已寫出 {out}({len(schema['paths'])} 條路徑)")

這支腳本從 /openapi.json 抽出 routes,寫成 Markdown。每次 deploy 前跑一次,docs/API.md 就會跟程式碼同步。我們刻意用純 Python 標準庫(json、urllib、pathlib),不引入額外依賴;這樣在 CI 任何環境都能跑。

驗收清單(升級版)與 PR 模板:

# 對應的 docs/acceptance.md(升級版)
ACCEPTANCE_MD = """
# 預約管理系統 上線驗收清單(v2)

## A. 開發者自查(PR 作者填)
- [ ] 本地端 `uv run pytest -v` 全部通過
- [ ] 本地端 `uv run ruff check` 沒有錯誤
- [ ] 本機 `docker compose up -d` 跑得起來
- [ ] 本機 `docker compose exec api alembic upgrade head` 無錯誤
- [ ] `curl http://localhost/health` 回 200
- [ ] 本次 PR 變更的所有 endpoint 都有對應測試
- [ ] 沒有未轉義的小於、大於、& 符號在程式碼區塊裡
- [ ] 沒有新增的固定金鑰 / mock token / 假網址

## B. 程式碼審查(Reviewer 填)
- [ ] 對應的 issue / spec 連結已附在 PR 描述
- [ ] 改動限制在討論範圍內,沒有無關重構
- [ ] 資料庫 migration 與模型定義一致
- [ ] 沒有新增 hardcoded URL / 假資料 / 模擬帳號
- [ ] 對 notification 路徑改動,確認 send 仍是模擬(無真實 SMTP / SMS 帳號洩漏)

## C. DBA 簽核(合併進 main 前)
- [ ] Alembic migration 跑過並可 downgrade
- [ ] 新增的索引列在 \`docs/INDEXES.md\`
- [ ] 預期資料量級已寫進備份大小估算

## D. SRE 簽核(部署到 production 前)
- [ ] Prometheus scrape 設定已更新
- [ ] runbook 已對應本次變更
- [ ] smoke test 計畫加進 deployment checklist
- [ ] on-call 知道這次部署的特性
"""

# 對應的 .github/PULL_REQUEST_TEMPLATE.md
PR_TEMPLATE = """
## 變更摘要
- 改了什麼(一句話)

## 對應議題 / 規格
- 連結:

## 變更類型
- [ ] 新功能
- [ ] bug fix
- [ ] 文件 / 註解
- [ ] 重構(無功能改變)
- [ ] 部署 / 維運

## 驗收(請逐項勾)
- [ ] `uv run pytest -v` 通過
- [ ] `uv run ruff check` 通過
- [ ] `curl /health` 回 200
- [ ] OpenAPI 摘要已更新(`python scripts/docs_gen_api_summary.py`)
"""
print(ACCEPTANCE_MD.strip())
print("---")
print(PR_TEMPLATE.strip())

這份升級版驗收清單分成 A/B/C/D 四個角色,每個角色的勾選條目不同:開發者自查範圍小(自己能驗證的)、Reviewer 看程式品質、DBA 看資料庫、SRE 看維運。對小型團隊來說可以簡化為 A+B+小段 C,但「分類」這個觀念本身就有價值:它逼你在合併前想清楚「誰要看這份 PR」。

常見錯誤與踩雷

第一個常見錯誤是「README 過於冗長」。一份 README 應該 5 分鐘內讀完;如果太長,請把細節拆到 docs/ 子目錄。我們今天的版本刻意控制在 80 行以內,重要段落都有「快速開始」段落讓新手第一時間看到。

第二個常見踩雷是「runbook 只有症狀、沒有指令」。只寫「檢查 DB」不夠,要寫「docker compose exec db pg_isready -U booking」。我們今天的範例每個處理步驟都有具體指令,方便值班工程師直接複製貼上。另一個常見變體是 runbook 寫了指令、但指令在 production 環境不能用(例如把 dev container 當主機)。對應處理:在 production 環境跑一遍所有 runbook 指令、發現不合實際的立刻修。

第三個是「OpenAPI 摘要沒有自動生成」。手刻 docs/API.md 一定會跟程式碼不同步,最常見的狀況是「新增了 endpoint 但忘記更新文件」。我們今天的 scripts/docs_gen_api_summary.py 把 OpenAPI 自動產生成 Markdown,CI 上每次 build 跑一次即可。我們的 `/openapi.json 來自 FastAPI 自動產生,永遠跟程式碼同步。

第四個是「驗收清單只給開發者」。如果只有開發者自查,沒有 Reviewer、DBA、SRE 的檢查環節,那些需要領域專業的問題(例如「這條 SQL 會不會 lock 表」、「這個 endpoint 會不會讓監控告警誤判」)就不會被發現。我們的 A/B/C/D 四角色版本就是強迫「該看的人要看」。

效能與實務提醒

文件品質比文件數量重要。一份精心寫的 50 行 README 遠勝過 500 行拼貼而成的 wiki。我們建議每個專案都把 README、RUNBOOK、API 摘要、驗收清單四份文件定為「必讀」,其餘細節留給程式碼與 commit history。

文件要跟程式碼一起進版控。我們刻意把 docs/API.md 與 docs/acceptance.md 放進 Git 儲存庫,PR 修改時一起 review;docs/API.md 從 /openapi.json 自動生成,docs/acceptance.md 與 RUNBOOK.md 是人手編輯但有 commit history 可追蹤。

runbook 的更新成本不可忽略。一份好的 runbook 在 production 一年會被更新 10–20 次(每次事件後都會調整),這表示「runbook 不是寫一次就結束」。我們建議把 runbook 與 Day 42 的監控指標綁定:每次新增告警時,同步更新 runbook 中對應的處置段落;每次事故復盤後,把新發現的處置步驟寫進 runbook。這樣 runbook 才能真的在凌晨三點救人。

最後,文件化不是工程師的「bonus」,而是 senior 與 junior 最大的差別之一:junior 工程師寫完程式碼就提交、senior 工程師則會花兩小時把程式碼變成「可以被接手」。今天的這份文件化工作,也是把一個人做的專案升級為「團隊可以共同維運」的關鍵。

底下是一支「CI 跑一次就把所有文件生成」的整合腳本:

# scripts/build_docs.py
# 在 CI 跑一次:把 docs/API.md 生成、跑驗收清單的自動可驗項、寫入 docs/BUILD.md
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path


def run(cmd: list[str]) -> str:
    """執行指令並回傳 stdout,失敗就 raise。"""
    print(f"$ {' '.join(cmd)}")
    r = subprocess.run(cmd, capture_output=True, text=True, check=True)
    return r.stdout


def build_api_summary(base_url: str) -> None:
    run([
        sys.executable, "scripts/docs_gen_api_summary.py",
        base_url, "docs/API.md",
    ])


def build_acceptance_record() -> None:
    today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    Path("docs/BUILD.md").write_text(
        f"# 自動驗收紀錄\n\n- 日期:{today}\n- API 摘要:已更新\n",
        encoding="utf-8",
    )


def main() -> int:
    build_api_summary("http://localhost")
    build_acceptance_record()
    print("所有文件已生成")
    return 0


if __name__ == "__main__":
    sys.exit(main())

這支腳本可以加進 scripts/build_docs.py,並在 CI 的 deploy job 跑一次:先起 stack、跑 build_docs.py、再寫進 docs/BUILD.md。如此一來,每次 deploy 都會留下「這次 deploy 有哪些文件更新」的可追蹤記錄。

# 在 Day 32 的 GitHub Actions workflow 加這段(節錄)
CI_STEP = """
- name: Build docs
  run: |
    docker compose up -d
    sleep 5
    python scripts/build_docs.py
- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: docs
    path: docs/
"""
print(CI_STEP.strip())

這兩段把「文件即程式」的觀念落實進 CI:deploy job 一跑就生成新文件,之後上傳成 artifact 留給 PR review 與發佈用。等 Day 45 系列收尾後,我們會在延伸資源中列出完整的 GitHub Actions 範本。

小結

今天把整套預約管理系統變成「可以被別人接手」的狀態。我們寫了 README.md(5 分鐘內可讀完的開發者指南)、RUNBOOK.md(五種常見事件的 step-by-step 處置手冊)、寫了 scripts/docs_gen_api_summary.py 從 OpenAPI 自動產生 API 規格摘要、把 Day 40 的驗收清單升級為 A/B/C/D 四角色版本、加上一支 scripts/build_docs.py 把整個文件生成流程自動化。所有文件都用 Markdown + UTF-8,與 README 規範一致;資料延續 Day 35–43 的虛構示範。明天 Day 45 是系列最後一篇,會回顧 45 天從「寫腳本」到「上線維運」的學習路徑,並列出延伸學習方向。

從「會寫程式」到「能被接手」是另一個層次的工程師價值。我們今天做的 4 份文件在小型團隊裡可能太多、在大型團隊裡可能不夠;但「先把這 4 份寫好、再依需求擴充」這條思路本身是有用的。我們預期接手這個 stack 的人在第一個月能上手(靠 README)、第一個事件發生時能復原(靠 runbook)、第二個月需要修改 API 時能對齊合約(靠 docs/API.md)。文件不是限制工程師,而是讓更多人能一起把專案做好。

結語

今天的重點是把「在原作者電腦裡跑得動的程式」變成「可以被別人接手」。README、runbook、API 摘要、驗收清單這四份文件看似瑣碎,但它們對 production 系統的可維運性有決定性的影響。明天 Day 45 我們會回顧整個 45 天學習路徑,從 Day 1 的 FastAPI 起步到 Day 44 的文件交接,把「從零到 production」的整套能力整理成一份索引,並列出幾個延伸學習的方向(分散式追蹤、k8s、observability stack 等)。整個系列至此告一段落,但你的後端工程師之路才剛剛開始。我們這 45 天做的不是「速成」而是「打底」:你會了 FastAPI 0.116、SQLModel、HTMX、Docker Compose、Prometheus、pg_dump、locust,這些能力堆起來就像工具箱,後續遇到任何後端問題都可以從裡面找答案。明天的系列總結會把這些內容再索引一次,幫助你日後快速複習。

另外寫文件這種事有一個小祕訣:每天花十分鐘把昨天處理的事寫成 1–2 句 commit message,每週花半小時把這週遇到的事寫成 runbook 更新。六個月後你就會有一份實戰級的 runbook,這是免費的(只要你每天持續寫)。我們今天寫的這份 runbook 是「地基」,未來每次事件都會讓它長出新的枝葉。明天 Day 45 開始,讓我們一起回顧 45 天的全景。

延伸資源

  • GitHub README 最佳實踐(2025):https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes,README 應該放什麼、怎麼分類。
  • Google SRE Book — Runbook 指南(2017,跨年代經典):https://sre.google/sre-book/eliminating-toil/,runbook 的撰寫原則與「可被替代」的概念。
  • FastAPI OpenAPI 官方說明(0.116,2025):https://fastapi.tiangolo.com/advanced/extending-openapi/,自訂 OpenAPI metadata 與 tags。
  • Conventional Commits(2024):https://www.conventionalcommits.org/zh-hant/,commit 訊息的標準格式,能讓文件與版本記錄整齊對應。
  • Keep a Changelog(2024):https://keepachangelog.com/zh-TW/1.1.0/,CHANGELOG.md 的標準寫法。

留言

這個網誌中的熱門文章

Day 2 變數與資料型別

Day 2 變數與資料型別 引言 寫程式的過程中,變數與資料型別是處理資料的基礎。變數是存放資料的容器,資料型別則決定這筆資料有哪些特性、可以進行哪些操作。學會定義變數、認識各種資料型別,是學好 Python 的關鍵一步。 這篇文章會帶你了解 Python 中變數的觀念、如何定義變數,以及常見的資料型別,包括整數、浮點數、字串、布林值,還有串列、元組、字典與集合等容器型別。我們也會介紹變數的命名規則與撰寫風格建議,以及如何用 type() 檢查資料型別。 什麼是變數?如何在 Python 中定義變數 變數是在程式執行時用來存放資料的名稱。透過定義變數,我們可以給一筆資料一個名字,並在程式的其他地方用這個名字取用該筆資料。在 Python 中,變數不需要事先宣告型別,因為 Python 是動態型別語言,變數的型別由指定給它的值決定。 定義變數的基本語法 在 Python 中定義變數非常簡單,只要用賦值符號 = 把值指定給變數即可。例如: x = 5 # 定義變數 x,並把整數 5 賦值給它 name = "Alice" # 定義變數 name,並把字串 "Alice" 賦值給它 在這裡,x 是一個變數,被賦予整數 5;name 是另一個變數,被賦予字串 "Alice"。 變數的更新與覆寫 變數的值可以修改,也就是說,我們可以在程式的不同地方給同一個變數新的值。例如: x = 10 # x 最初被賦予 10 x = 15 # x 的值現在被更新為 15 這樣就能依照需求,在程式執行過程中靈活調整變數的值。 Python 的動態型別系統 Python 和某些靜態型別語言不同,定義變數時不需要宣告型別。賦值時,Python 會根據值自動判斷變數的型別。例如: x = 5 # x 是整數 x = 3.14 # x 變成浮點數 x = "Hi" # x 變成字串 同一個變數在程式執行過程中可以存放不同型別的值,這是 Python 的彈性之一。 常見資料型別 在 Python 中,資料型別決定我們可以對變數進行哪些操作...

Day 1 Python 簡介與環境設定

Day 1 Python 簡介與環境設定 引言 在現在的科技環境裡,程式設計已經是一項重要技能。無論你是對資料科學有興趣、想成為開發者,或是想踏入人工智慧(AI)領域,學會寫程式都能明顯提升你的競爭力。在眾多程式語言中,Python 因為語法簡單、功能強大、應用範圍廣泛,成為許多人進入程式世界的第一選擇。這篇文章會帶你認識 Python 的背景與優勢,並一步步教你在不同系統上安裝與設定 Python 開發環境,最後寫出第一支 Python 程式。 為什麼選擇 Python? Python 是一種高階程式語言,由 Guido van Rossum 在 1991 年發布。Python 的設計哲學強調程式碼的可讀性,並用縮排來定義程式區塊,這點和許多使用大括號的語言不同。簡潔的語法讓它成為初學者的理想選擇;就算是經驗豐富的開發者,也能用它完成複雜的專案。 Python 的優勢如下: 簡單易學 :Python 的語法清楚、結構簡潔,初學者很快就能上手。和其他語言相比,學習曲線相對平緩,不需要先弄懂一堆複雜觀念,就能開始寫程式。 應用範圍廣泛 :從資料科學、網頁開發、人工智慧、機器學習、自動化測試到網路爬蟲,Python 都有大量開源函式庫與工具支援,而且在這些領域都扮演關鍵角色。 豐富的函式庫與框架 :Python 的函式庫生態系非常龐大。做資料分析有 NumPy、Pandas;開發網站有 Django、Flask;做深度學習有 TensorFlow、PyTorch。各種需求幾乎都能找到對應的套件,讓開發更有效率。 跨平台支援 :Python 支援 Windows、macOS、Linux 等作業系統,程式通常不需要太多修改就能跨平台執行,讓開發與部署更有彈性。 活躍的社群 :Python 擁有龐大的開發者社群。學習或開發上遇到問題,幾乎都能在社群與論壇(例如 Stack Overflow)找到答案,對初學者來說是很強的後盾,也能減少卡關時的挫折感。 Python 的應用領域 Python 的流行與強大功能,讓許多領域都開始大量使用它。以下是幾個常見的應用方向: 資料科學 :隨著大數據與人工智慧興起,資料科學大量使用 Python。NumPy、Pandas 與 Matplotlib 等工具能處理和分析龐...

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門

Python 從入門到 PyTorch 深度學習:開啟 AI 世界的大門 隨著人工智慧(AI)與深度學習(Deep Learning)快速發展,越來越多人對這些技術產生興趣。不論你是想踏入 AI 領域的初學者,還是已經有程式基礎的開發者,學好 Python 與深度學習框架(例如 PyTorch),都能為你打開更多可能。 為什麼選擇 Python? Python 已經是資料科學與人工智慧領域的首選語言。它的語法簡潔、容易上手,而且擁有龐大的生態系與大量開源函式庫。無論是資料處理、資料視覺化,還是建立機器學習與深度學習模型,Python 都能勝任。對想進入 AI 或資料科學領域的人來說,它幾乎是必備工具。 PyTorch 是什麼? PyTorch 是由 Meta(原 Facebook)AI 研究團隊開發的開源深度學習框架,以易用、靈活和動態計算圖著稱,是許多 AI 研究人員與開發者的首選。相較於其他框架,PyTorch 的寫法更貼近原生 Python,對初學者相對友善。無論是簡單的實驗,還是複雜的深度學習模型,PyTorch 都能提供強大的支援。 這個系列能帶給你什麼? 這個系列會從 Python 的基礎開始,帶你一步一步學習,最後能自己用 PyTorch 建立深度學習模型。即使你完全沒有寫過程式,也能跟著文章的節奏累積技能,理解 AI 與深度學習的核心觀念。 本系列涵蓋的主題 Python 基礎:從變數、條件判斷到函式與模組。 資料處理工具:用 NumPy 與 Pandas 有效率地操作資料。 資料視覺化:用 Matplotlib 與 Seaborn 把資料畫成圖表。 深度學習的數學基礎:線性代數、微積分與機率。 PyTorch 入門:理解張量、模型建構與 GPU 加速。 基礎深度學習模型:CNN 與 RNN 的實作應用。 深度學習專案實戰:從資料前處理到模型部署的端到端流程。 誰適合這個系列? 程式初學者 :如果你對 AI 充滿好奇,卻還沒寫過程式,系列的第一部分會帶你快速上手 Python,並幫助你理解深度學習的基本觀念。 資料科學愛好者 :如果你已經熟悉一些資料處理方法,進階部分會教你如何用 PyTorch 建構深度學習模型。 開發者與研究人員 :想更深入了...