09 / 90

Day 09:列表、字典、頻率統計與安全的 Git 復原

新內容:列表與字典、字元頻率統計(空、重複和 Unicode 碼位的情況)、捨棄未提交修改與撤銷(revert)已提交修改的區別,以及獨立實作文字統計。間隔複習會再次用到第 08 天的不變量和第 05 天的別名。

自主學習與 Python 480 分鐘(8 小時專注學習)
01 120 分鐘

列表與字典:有序元素與鍵值計數

代理協助練習:先寫下自己的預測和實際輸出,之後才可以請 AI 代理解釋或審閱,並且必須在證據中記錄所受的協助。

先決條件

已完成第 08 天(包括其獨立檢查)。復原:第 08 天(迴圈與不變量)、第 07 天活動 1(修改與重新綁定);第 07 天是本單元的複習日。

學習目標

建立並更新列表和字典,檢查成員關係,用 get 安全讀取不存在的鍵,並預測兩個名稱指向同一列表時的別名效果,包括空和 Unicode 的情況。

操作說明

學習來源:在本活動現有的閱讀與練習時段內,參考 Automate the Boring Stuff with Python, 3rd edition 的 Chapter 6; Practice Questions; Appendix B answers,用自己的話解釋一處與本地任務的聯繫。保留現有練習與驗收檢查;若外部資料無法存取,使用課程自寫的解釋。間隔複習暖身: 憑記憶說出第 08 天的計數不變量,並解釋為什麼 a = [1]; b = a; a.append(2) 會改變 b。今天你會在列表上看到同樣的別名現象。

新概念: list(text) 回傳由碼位組成的列表。列表保持元素順序,append 在尾端加入。字典把鍵對應到值;d[key] = value 用於新增或取代,key in d 檢查鍵是否存在,d.get(key, 0) 在鍵不存在時回傳 0 而不是報錯。字典會記住插入順序。

先預測印出的每一行,再執行:

chars = list("ñu猫")
print(chars, len(chars))
print(len("n\u0303u"), "n\u0303u" == "ñu")
seen = []
for ch in "abca":
    if ch not in seen:
        seen.append(ch)
print(seen)
ages = {}
ages["猫"] = 3
ages["犬"] = 5
ages["猫"] = ages["猫"] + 1
print(ages, len(ages), "猫" in ages, ages.get("鳥", 0))
alias = seen
alias.append("z")
print(seen)
print(list(""), {})

練習與預測紀錄

寫下全部六行輸出的預測,再記錄實際輸出。解釋為什麼 len("n\u0303u") 為 3、為什麼 seen 只保留每個字元的第一次出現,以及為什麼透過 alias 追加也會改變 seen。

獨立掌握標準

六行都在執行前預測並逐一解釋不符;能解釋帶預設值的 get、插入順序、分解字元的長度以及列表別名。

來源資源與出處

linking Copyright Al Sweigart; edition-specific reuse terms unverified linking only; no reproduction

Automate the Boring Stuff with Python, 3rd edition

作者 / 機構: Al Sweigart | 原始出處連結 ↗

對應章節 / 時間戳: Chapter 6; Practice Questions; Appendix B answers

驗證版本與日期: Public edition checked 2026-11-01; moving pages may change

入選理由:

Beginner teaching and answer-keyed practice before checking exact semantics in the Python reference; selected chapters only, not the book's entire automation stack.

來源前置條件:

No prior programming required for Chapter 1; later chapters assume its basic Python concepts.

安全回退方案(離線彈性):

Use the original localized explanations, exercises and checks already present in this activity; no external account or purchase is required for that fallback.

對比候選資源與選型分析 (2)
The Python Tutorial ↗ compared_alternative [PSF License Version 2]

Guided Python syntax but assumes programming familiarity; paired with the beginner text rather than used as its replacement.

MIT OCW 6.0001 ↗ compared_alternative [CC BY-NC-SA 4.0]

Lectures and problem sets teach a broader CS1 course; the book offers shorter text-first entry and an answer appendix.

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

作者 / 機構: Python Software Foundation | 原始出處連結 ↗

對應章節 / 時間戳: 第 4.2–4.10 節(for、range、定義函式);資料結構見同一教學第 5 章

驗證版本與日期: Python 3.12 文件(核驗日期:2026-10-30)

入選理由:

用於查閱 Python 迭代、函式和容器的第一手參考資料。

來源前置條件:

第 01–06 天的 Python 運算式與檔案系統基礎

安全回退方案(離線彈性):

教材內已說明所有必需的行為,可以離線完成。

對比候選資源與選型分析 (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

在語法層面定義相同的結構;選擇教學章節是因為它循序漸進。

以講座節奏講解相同的控制流程;由於本課程已透過終端機練習推進這些概念,暫不採用。

02 120 分鐘

用字典統計頻率及其不變量

代理協助練習:先寫下自己的預測和實際輸出,之後才可以請 AI 代理解釋或審閱,並且必須在證據中記錄所受的協助。

先決條件

今天的活動 1。復原:第 08 天活動 1(計數不變量)和今天的活動 1(字典 get)。

學習目標

實作 char_frequencies(text) 和 most_common(counts),陳述字典不變量,並以碼位為單位測試空、重複、區分大小寫、表情符號和分解形式 Unicode 的輸入。

操作說明

學習來源:在本活動現有的閱讀與練習時段內,參考 Automate the Boring Stuff with Python, 3rd edition 的 Chapter 7; Practice Questions; Appendix B answers,用自己的話解釋一處與本地任務的聯繫。保留現有練習與驗收檢查;若外部資料無法存取,使用課程自寫的解釋。間隔複習: 這是把第 08 天的單一計數器推廣為每個不同字元各一個計數器。

不變量: 每次迭代開始時,counts 把目前已走訪的每個碼位對應到它被走訪的次數,且所有值的總和等於已走訪的碼位數。most_common 保存目前計數最大的字元;只有嚴格更大的計數才會取代它,所以並列時保留較早出現的字元。

執行前預測每一行,並為 "banana" 寫出追蹤表(ch / counts):

def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
def most_common(counts):
    best_char = None
    best_count = 0
    for ch in counts:
        if counts[ch] > best_count:
            best_char = ch
            best_count = counts[ch]
    return best_char
print(char_frequencies(""))
print(char_frequencies("banana"))
print(char_frequencies("猫猫犬"))
print(char_frequencies("aA"))
print(char_frequencies("😀😀"))
print(char_frequencies("e\u0301") == {"e": 1, "\u0301": 1})
print(most_common(char_frequencies("banana")))
print(most_common(char_frequencies("abab")))
print(most_common(char_frequencies("")))

練習與預測紀錄

提交 char_frequencies("banana") 的追蹤表、全部九行輸出的預測與觀察,並各用一句話解釋:為什麼 "aA" 得到兩個鍵,為什麼 "😀😀" 的計數是 2,為什麼空字串得到 {} 和 None。

獨立掌握標準

追蹤表與參考一致;九行都預測正確或解釋了不符;陳述了字典不變量和並列規則;正確處理空、重複、大小寫和 Unicode 的情況。

來源資源與出處

linking Copyright Al Sweigart; edition-specific reuse terms unverified linking only; no reproduction

Automate the Boring Stuff with Python, 3rd edition

作者 / 機構: Al Sweigart | 原始出處連結 ↗

對應章節 / 時間戳: Chapter 7; Practice Questions; Appendix B answers

驗證版本與日期: Public edition checked 2026-11-01; moving pages may change

入選理由:

Beginner teaching and answer-keyed practice before checking exact semantics in the Python reference; selected chapters only, not the book's entire automation stack.

來源前置條件:

No prior programming required for Chapter 1; later chapters assume its basic Python concepts.

安全回退方案(離線彈性):

Use the original localized explanations, exercises and checks already present in this activity; no external account or purchase is required for that fallback.

對比候選資源與選型分析 (2)
The Python Tutorial ↗ compared_alternative [PSF License Version 2]

Guided Python syntax but assumes programming familiarity; paired with the beginner text rather than used as its replacement.

MIT OCW 6.0001 ↗ compared_alternative [CC BY-NC-SA 4.0]

Lectures and problem sets teach a broader CS1 course; the book offers shorter text-first entry and an answer appendix.

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

作者 / 機構: Python Software Foundation | 原始出處連結 ↗

對應章節 / 時間戳: 第 4.2–4.10 節(for、range、定義函式);資料結構見同一教學第 5 章

驗證版本與日期: Python 3.12 文件(核驗日期:2026-10-30)

入選理由:

用於查閱 Python 迭代、函式和容器的第一手參考資料。

來源前置條件:

第 01–06 天的 Python 運算式與檔案系統基礎

安全回退方案(離線彈性):

教材內已說明所有必需的行為,可以離線完成。

對比候選資源與選型分析 (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

在語法層面定義相同的結構;選擇教學章節是因為它循序漸進。

以講座節奏講解相同的控制流程;由於本課程已透過終端機練習推進這些概念,暫不採用。

03 120 分鐘

安全的 Git 復原:還原未提交的修改,撤銷已提交的修改

代理協助練習:先寫下自己的預測和實際輸出,之後才可以請 AI 代理解釋或審閱,並且必須在證據中記錄所受的協助。

先決條件

今天的活動 1–2;已安裝 Git。復原:第 07 天活動 3 和第 08 天活動 3(git restore)。

學習目標

在拋棄式儲存庫中為每種情況選擇正確的安全工具:未提交的修改用 git restore(或儲存的副本),已提交的修改用 git revert --no-edit HEAD,並逐一驗證結果。

操作說明

間隔複習: A 部分用今天的頻率檔案重複第 07–08 天的 git restore 流程。

新概念: git revert 會建立一個新提交來抵銷先前的某個提交,因此歷史被保留而不是被改寫。它只作用於已提交的修改;當工作目錄中受影響的檔案有未提交修改時,它會拒絕執行。這正是為什麼不能先提交基準版本、再做未提交的修改、然後嘗試 git revert。

每個部分使用一個新的暫存目錄,並先預測每一項輸出。

A 部分:用 Git 還原未提交的修改

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print(char_frequencies(""))\n' >> freq.py
git status --short
python3 freq.py
git restore freq.py
git status --short
python3 freq.py

A 部分的替代方法:儲存的副本(復原時不需要 Git 指令)

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
cp freq.py freq.py.saved
printf 'oops\n' >> freq.py
cp freq.py.saved freq.py
rm freq.py.saved
git status --short
python3 freq.py

B 部分:用新提交撤銷已提交的修改

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print("debug")\n' >> freq.py
git commit -q -am "Add debug print"
python3 freq.py
git revert --no-edit HEAD > /dev/null
git log --format=%s
git diff HEAD~2 HEAD
git status --short
python3 freq.py

C 部分:為什麼順序很重要:示範存在未提交修改時 git revert 會拒絕執行。

cd "$(mktemp -d)"
git init -q
git config user.name "Learner"
git config user.email "[email protected]"
cat > freq.py <<'EOF'
def char_frequencies(text):
    counts = {}
    for ch in text:
        counts[ch] = counts.get(ch, 0) + 1
    return counts
print(char_frequencies("猫猫犬"))
EOF
git add freq.py
git commit -q -m "Add char_frequencies"
python3 freq.py
printf 'print("debug")\n' >> freq.py
git commit -q -am "Add debug print"
printf 'oops\n' >> freq.py
git revert --no-edit HEAD 2> /dev/null || echo "revert refused: uncommitted change present"
git status --short

練習與預測紀錄

每個部分都記錄預測與實際輸出。然後回答:哪個指令撤銷未提交的修改,哪個指令撤銷已提交的修改,什麼能證明每次復原成功,以及 C 部分中 git revert 為什麼拒絕執行。含 Unicode 的輸出 {'猫': 2, '犬': 1} 在修改前和復原後必須完全相同。

獨立掌握標準

三個部分都在拋棄式儲存庫中重現了參考輸出;正確地把未提交修改對應到 git restore 或儲存的副本、把已提交修改對應到 git revert --no-edit HEAD,展示了各自的驗證方法,並解釋了 C 部分的拒絕。

來源資源與出處

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

作者 / 機構: Python Software Foundation | 原始出處連結 ↗

對應章節 / 時間戳: 第 4.2–4.10 節(for、range、定義函式);資料結構見同一教學第 5 章

驗證版本與日期: Python 3.12 文件(核驗日期:2026-10-30)

入選理由:

用於查閱 Python 迭代、函式和容器的第一手參考資料。

來源前置條件:

第 01–06 天的 Python 運算式與檔案系統基礎

安全回退方案(離線彈性):

教材內已說明所有必需的行為,可以離線完成。

對比候選資源與選型分析 (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

在語法層面定義相同的結構;選擇教學章節是因為它循序漸進。

以講座節奏講解相同的控制流程;由於本課程已透過終端機練習推進這些概念,暫不採用。

04 120 分鐘

獨立實作文字統計

獨立掌握檢查:提交證據之前不使用任何 AI 協助,也不查看參考答案;如實申報所受的協助。

先決條件

已完成今天的活動 1–3 並記錄證據。復原:活動 2(頻率)、第 08 天活動 2(函式契約)、第 07 天(條件複習)。

學習目標

在無協助的情況下實作 text_stats(text),回報碼位長度、不同碼位的個數、頻率字典和出現最多的碼位;對空、重複和 Unicode 文字都正確,並且可以安全地重複呼叫。

操作說明

間隔複習: 本活動把第 08 天的迴圈不變量和函式與今天的字典結合起來。提交證據之前,不要打開參考答案,也不要使用 AI。

text_stats(text) 的規格(回傳恰好包含以下鍵的字典):
- "code_points":text 中 Unicode 碼位的個數(len(text))。
- "distinct":不同碼位的個數。
- "frequencies":從每個碼位到其出現次數的字典,按首次出現的順序排列。
- "most_common":出現次數最多的碼位;並列時取最先出現的;空文字時為 None。
嚴格以 Unicode 碼位計數:不做大小寫折疊,也不做正規化,所以 "e\u0301" 是兩個碼位。每次呼叫都必須從全新的狀態開始。

寫程式之前,先預測 ""、"abca"、"😀😀a" 和 "naïve naïve" 的完整結果,以及 "e\u0301" 的 code_points、distinct 和 most_common。然後實作、測試,最後寫出頻率迴圈和最多值迴圈各自的不變量。

練習與預測紀錄

提交:全部五個輸入的預測、text_stats 程式碼、實際輸出、兩次呼叫 text_stats("abca") 結果相等的檢查,以及兩個不變量。每一處不符都寫明你要回顧的復原活動。

獨立掌握標準

無協助:text_stats 在全部五個輸入(包括空、重複、表情符號、帶重音和分解形式的文字)上以碼位為單位與參考輸出一致;重複呼叫結果相等;兩個不變量陳述正確;每一處不符都寫明復原活動。

來源資源與出處

linking PSF License Version 2

The Python Tutorial: More Control Flow Tools

作者 / 機構: Python Software Foundation | 原始出處連結 ↗

對應章節 / 時間戳: 第 4.2–4.10 節(for、range、定義函式);資料結構見同一教學第 5 章

驗證版本與日期: Python 3.12 文件(核驗日期:2026-10-30)

入選理由:

用於查閱 Python 迭代、函式和容器的第一手參考資料。

來源前置條件:

第 01–06 天的 Python 運算式與檔案系統基礎

安全回退方案(離線彈性):

教材內已說明所有必需的行為,可以離線完成。

對比候選資源與選型分析 (2)
The Python Language Reference: Compound statements ↗ compared_alternative [PSF License Version 2]

在語法層面定義相同的結構;選擇教學章節是因為它循序漸進。

以講座節奏講解相同的控制流程;由於本課程已透過終端機練習推進這些概念,暫不採用。