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]

在语法层面定义相同的结构;选择教程章节是因为它循序渐进。

以讲座节奏讲解相同的控制流;由于本课程已通过终端练习推进这些概念,暂不采用。