Python 資料全景課 / 第四部分 應用 · M12

M12 設定檔的世界

你每天用的工具,背後都有設定檔:VS Code、GitHub、Docker、Claude Code,甚至這個課程網站本身。它們全部是 JSON、YAML 或 TOML。學完前面十二個單元,這些檔案你已經讀得懂;這個單元教你安全地改它們。
約 45 分鐘練習 notebook 1 個先修:M11
學完本單元,你能夠:
  1. 認出常見工具的設定檔用哪種格式、放在哪裏;
  2. 讀懂 VS Code 的 settings.json、GitHub Actions 的 workflow、docker-compose 和 Markdown 的 frontmatter;
  3. 認出這些設定檔裏 M8–M10 講過的陷阱,例如 python-version: 3.10 變成 3.1;
  4. 改設定檔前後用程式檢查,一次只改一處。

1設定檔無處不在 Configuration everywhere

打開這個課程網站自己的倉庫,設定檔比課程內容還多:

圖 1 這個課程網站的倉庫裏,哪些是設定檔、用哪種格式、給哪個工具讀。課程內容(Markdown)反而只是其中一部分。
圖 1 這個課程網站的倉庫裏,哪些是設定檔、用哪種格式、給哪個工具讀。課程內容(Markdown)反而只是其中一部分。
工具 設定檔 格式 寫給誰讀
VS Code .vscode/settings.json、tasks.json JSON(准許註解) 編輯器
GitHub Actions .github/workflows/*.yml YAML GitHub 的伺服器
Docker compose.yaml YAML Docker
Python 專案 pyproject.toml(M1) TOML uv、pip
Markdown 文件 檔案開頭 --- 之間 YAML 網站產生器、Obsidian
Claude Code .claude/settings.json JSON Claude Code

格式你都學過了。分別在於:每個工具只認自己那一套鍵名,而且各自有些自己的規矩。

2VS Code:准許註解的 JSON VS Code: JSON with comments

這個課程倉庫的 .vscode/settings.json(節錄):

{
  // Markdown:Tab 鍵展開本課的 snippets
  "[markdown]": {
    "editor.tabCompletion": "onlySnippets",
    "editor.wordWrap": "on"
  },
  "liveServer.settings.port": 5501
}

M8 說過 JSON 不准寫註解,用 json.loads 讀它果然報錯:

JSONDecodeError: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)

因為 VS Code 的設定檔不是嚴格的 JSON,而是 JSONC(JSON with Comments):准許 // 和 /* */ 註解。給人改的設定檔需要註解,所以 VS Code 放寬了規則。

VS Code 編輯這些檔案時,會用 JSON Schema(M10)檢查:鍵名打錯,下面會出現波浪線;輸入時會自動列出可用的設定。這就是 M10 那套方法在日常工具裏的樣子。

3GitHub Actions:YAML 的陷阱 GitHub Actions

GitHub Actions 讓 GitHub 在你 push 之後自動執行檢查。設定寫在 .github/workflows/ 裏的 YAML 檔:

name: 檢查課程網站
on:
  push:
    branches: [main]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4          # 取出倉庫的內容
      - uses: actions/setup-python@v5      # 安裝 Python
        with:
          python-version: "3.12"
      - run: python tools/build.py --check
flowchart LR
    E["on:push 到 main"] --> J["job:check<br/>runs-on: ubuntu-latest"]
    J --> S1["step 1<br/>取出倉庫"]
    S1 --> S2["step 2<br/>安裝 Python 3.12"]
    S2 --> S3["step 3<br/>build.py --check"]
    classDef e fill:#f1f1ef,stroke:#d3d1cb,color:#37352f
    classDef s fill:#ffffff,stroke:#d3d1cb,color:#37352f
    class E,J e
    class S1,S2,S3 s
圖 2 一個 workflow 的結構:on 寫甚麼時候執行;jobs 是要做的工作,每個 job 在一部新的機器上,按次序執行 steps。

這類檔案常見兩個 M9 的陷阱:

4docker-compose:端口要加引號 docker-compose: quote your ports

Docker 用 compose.yaml 描述要執行哪些服務:

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"        # 本機 8080 → 容器 80
      - "2222:22"        # 本機 2222 → 容器 22(SSH)

ports 的寫法是「本機端口:容器端口」。不加引號會怎樣?用 PyYAML 實測:

寫的 讀到
- 8080:80 '8080:80'(字串,沒事)
- 2222:22 133342(六十進制:2222×60+22)

冒號後面的數字小於 60,就會被當成六十進制(M9 的 9:30)。這是 PyYAML 和其他跟舊版 YAML 1.1 的工具的讀法;YAML 1.2 已經沒有六十進制(見 M9 的「YAML 1.1 與 1.2」)。但你無法保證每個讀這份檔的程式都跟 1.2,所以端口一律加引號,不用逐個判斷。

5Markdown 的 frontmatter Markdown frontmatter

這個課程的每一個單元,都是一個 Markdown 檔,開頭有一段用 --- 包住的 YAML,叫做 frontmatter:

---
title: 設定檔的世界
time: 約 45 分鐘
goals:
  - 認出常見工具的設定檔用哪種格式、放在哪裏;
---

## 設定檔無處不在 …

網站產生器(包括本課的 tools/build.py)和 Obsidian 都這樣用:frontmatter 放這份文件的資料(標題、日期、標籤),下面才是內容。讀它的方法很簡單:用 --- 切開,中間那段交給 yaml.safe_load。本課的建置腳本就是這樣做的。

6Claude Code 的設定 Claude Code settings

Claude Code 的設定是 JSON,分三層,越下面越優先:

檔案 範圍 放進 Git 嗎
~/.claude/settings.json 你自己,所有專案 不(在你的家目錄)
.claude/settings.json 這個專案,全組人共用 放
.claude/settings.local.json 這個專案,只限你自己 不放

公司或學校的管理員還可以在這三層之上加一層受管理的設定(managed settings),它優先於這三層,個人和專案的設定都蓋不過它。

最常改的是權限,例如准許它執行哪些命令、禁止它讀哪些檔案:

{
  "permissions": {
    "allow": ["Bash(python3 tools/build.py:*)"],
    "deny": ["Read(./.env)"]
  }
}

這三層的分法,在很多工具裏都見到:個人設定、專案設定、只在自己電腦上的設定。密碼、API key 這類秘密,永遠不要寫進會放進 Git 的設定檔;要用的話,放在不入 Git 的檔案或環境變數裏。

7安全地修改設定檔 Editing config files safely

設定檔寫錯了,工具可能啟動不了,也可能靜靜地用錯的設定執行(M9 的挪威)。改之前、改之後,花一分鐘檢查:

flowchart LR
    A["先 commit"] --> B["只改一處"]
    B --> C["用程式讀"]
    C -->|"報錯"| B
    C -->|"讀得到"| D["印出型別"]
    D --> E["讓工具使用"]
    classDef s fill:#ffffff,stroke:#d3d1cb,color:#37352f
    class A,B,C,D,E s
圖 3 修改設定檔的安全流程。每一步都很短,但能擋下大部分錯誤。
  1. 先 commit(git-course 的習慣):改壞了,一句命令就能退回;
  2. 一次只改一處:出問題時,你知道是哪一處;
  3. 用程式讀一次:json.loads、yaml.safe_load、tomllib.loads,語法錯誤立即現形;
  4. 印出改了的值和型別:抓 M9 那種「合法但猜錯」的錯誤;有 schema 的話,跑一次驗證(M10);
  5. 最後才讓工具使用新的設定。

連這一頁也不例外:本頁開頭的 frontmatter,學習目標裏有一句提到 python-version: 3.10。那個「冒號+空格」令 YAML 把整句讀成一個 dict,建置當場失敗。修法正是 M9 的規則:整句加引號。之後建置腳本加了一道檢查,學習目標不是文字就清楚地報出是哪一句。

8容易混淆 Easily confused

這兩樣 分別
JSON 和 JSONC 後者准許註解,是 VS Code 等工具用的;json.loads 讀不了。
GitHub 讀 on: 和 PyYAML 讀 on: GitHub 當它是鍵名 on;PyYAML 當它是 True。
python-version: 3.10 和 "3.10" 前者讀成 3.1;後者才是 3.10。
8080:80 和 2222:22 前者 PyYAML 讀到字串;後者被跟 YAML 1.1 的工具(例如 PyYAML)讀成 133342。兩者都應加引號。
settings.json 和 settings.local.json 前者全組共用、放進 Git;後者只限自己、不放。
frontmatter 和內文 前者是 --- 之間的 YAML 資料;後者是文件內容。

9動手:設定檔巡禮 Hands-on: a tour of config files

  1. 下載 m12-config-tour.ipynb 和 m12-configs.zip,放進 python-course 資料夾;
  2. 執行 uv run jupyter lab,打開 notebook,逐格執行。

zip 裏有小書店網站的五個設定檔:VS Code 設定、GitHub Actions workflow、docker-compose、一篇有 frontmatter 的網誌文章、Claude Code 設定。每個檔都藏了一個這單元講過的問題。你要逐個讀入、找出問題、修好,並寫一個函式,一次檢查全部設定檔。

工程線(選做)

m12-pipeline-eng.ipynb 和 pipeline.yaml:一份資料處理流程的設定檔,列出每個階段的腳本、輸入和輸出。用 JSON Schema 檢查格式,再用程式檢查「每個階段需要的輸入,前面的階段都有產生」。

下一步

M13 綜合專案:從香港天文台的開放資料取得真實的天氣 JSON,整理、統計、畫圖,寫成一份 notebook 報告,把整門課用過的工具串起來。