值、名称与表达式
变量名称引用值,赋值绑定名称,并非永久成立的等式。x=3、y=x、x=4 后 y 仍为 3。表达式产生值,+ 加法,== 比较,and/or 组合条件。类型决定操作意义:'3'+'4' 拼接文字,3+4 则整数相加。应明确转换外部文字并处理转换错误。
上述赋值后 y 是多少?
完整解答
3;重新绑定 x 不会重新绑定 y。
选择与重复
if 选择分支,for 遍历集合,while 在条件为真时重复。Python 通过缩进组织语句。空集合使 for 执行零次。while 需要推进理由:count<3 并每次 count+=1 会结束,忘记增加则不会。break 离开循环,continue 开始下一迭代,return 离开函数;用轨迹表区分这些边界。
真条件 while 循环缺少递增会怎样?
完整解答
没有其他退出或状态变化时,不会终止。
集合与修改
列表提供有序项目,字典把键映射到值。图书可表示为 {'id':1,'title':'Dune'}。多个名称可引用同一个可变对象:b=a 不复制列表,因此 b.append 会改变 a 看到的对象。a.copy 创建新的外层列表,但嵌套记录仍共享。明确函数修改参数还是返回新数据。遍历时避免改变列表长度,可构造筛选后的结果。
复制列表会复制所有嵌套字典吗?
完整解答
浅复制只复制外层容器。
函数与接口
函数包含参数、函数体与结果。局部名称把临时状态限制在调用内。返回数据供调用者使用;print 产生输出,不能代替返回值。把搜索放入函数,由独立 main 解析命令行并打印。这样终端、测试和后续服务器可复用同一逻辑。__name__ 守卫让直接运行时启动接口,导入时不启动。
为什么搜索应返回记录而非直接打印?
完整解答
不同调用者可格式化、测试或传输同一结果。
错误与调试
语法错误阻止解析,运行时异常表示操作失败,逻辑错误可能不抛异常却给出错误结果。从失败操作沿回溯查看调用者。用最小输入复现,说明预期,检查中间值,再修复原因。只在能够合理响应的位置捕获具体异常。用户输入应在边界验证;断言可能被禁用,不能充当输入验证。
应使用 assert 验证用户价格吗?
完整解答
不应。明确拒绝无效输入,因为断言可被禁用。
常见误解
- 浅复制不能隔离嵌套可变对象。
- 捕获所有异常后继续可能掩盖错误状态。
实验准备
下载脚本,在终端中使用 Python 3.11 或更新版本运行:python m03_catalogue.py. Windows 也可使用 py -3;部分系统使用 python3。实验仅用标准库。先预测结果,再运行并完成变体。不要使用 -O,以保留断言。下方输出由构建器实际运行捕获,两种语言使用相同代码与输出。
实验 1 — 命令行目录
运行默认查询,再传入命令行参数 FOUNDATION。列表推导生成结果,不修改输入。
"""Separate reusable catalogue logic from a command-line interface."""
import argparse
def find_titles(books, query):
query = query.strip().casefold()
if not query:
raise ValueError("query must not be blank")
return [book for book in books if query in book["title"].casefold()]
def main():
parser = argparse.ArgumentParser(description="Search a small catalogue")
parser.add_argument("query", nargs="?", default="dune")
args = parser.parse_args()
books = [{"id": 1, "title": "Dune"}, {"id": 2, "title": "Foundation"}]
for book in find_titles(books, args.query):
print(f'{book["id"]}: {book["title"]}')
assert find_titles(books, "FOUND") == [books[1]]
assert find_titles(books, "missing") == []
if __name__ == "__main__":
main()
1: Dune
- 查询不存在的书名。
- 传入引号包围的空白查询。
- 增加作者字段及独立作者搜索函数。
完整解答
缺失目标不打印记录。空白输入抛出 ValueError,否则空子串会匹配所有项。作者搜索可复用规范化规则,但读取 book['author'],验证逻辑与命令行接口分离。
实验 2 — 观察状态与复制
逐条预测列表。+ 表达式返回新列表,append 修改现有列表。
"""Observe aliasing, copies, function return values and validation."""
def add_book(books, title):
clean = title.strip()
if not clean:
raise ValueError("blank title")
return books + [clean]
original = ["Dune"]
alias = original
alias.append("Foundation")
print("after alias append:", original)
updated = add_book(original, " Solaris ")
print("original:", original, "updated:", updated)
assert original == ["Dune", "Foundation"]
assert updated == ["Dune", "Foundation", "Solaris"]
try:
add_book(original, " ")
except ValueError:
print("blank title rejected")
else:
raise AssertionError("must reject blank input")
after alias append: ['Dune', 'Foundation']
original: ['Dune', 'Foundation'] updated: ['Dune', 'Foundation', 'Solaris']
blank title rejected
- 把别名赋值改为 original.copy()。
- 改成修改参数并更新约定与测试。
- 解释验证为何先于更新。
完整解答
复制后追加 Foundation 不改变 original 的 [Dune]。修改版本可 append 后返回 None,但测试应预期原列表变化。先验证可避免部分应用无效请求。
练习与完整解答
先尝试,再展开解答。★ 应用概念;★★ 结合概念;★★★ 进行设计或证明。
跟踪 a=2、b=a、a=a+1。
完整解答
a=3、b=2,最后仅重新绑定 a。
对 17、18、19 求 age>=18。
完整解答
False、True、True。边界案例可区分 > 与 >=。
从 total=0 开始逐项累加 [2,4,6]。
完整解答
状态为 2、6、12;空列表使总和保持零。
b=a 后 b.append('B'),为什么 a 改变?
完整解答
两个名称引用同一列表。把 b 绑定到新列表不同于修改共享列表。
函数打印 7 但没有 return,调用者收到什么?
完整解答
None。打印是副作用,不是返回值。
为什么 strip 后验证,而非仅检查原字符串?
完整解答
空格字符串在 strip 前非空,处理后为空;应验证函数实际使用的规范化值。
设计不打印、不修改输入的价格筛选函数。
完整解答
接受图书和非负整数价格上限,返回满足 b['price_cents']<=limit 的列表。需说明返回的字典仍共享,除非另外复制。
搜索意外匹配所有书,如何最小化调查?
完整解答
用一本书与空白查询复现,检查规范化后的查询。空子串属于所有字符串;增加边界验证与回归案例。
自测
选择答案查看反馈,重置后可重做。无需 JavaScript 也可阅读答案表。
= 做什么?
哪个离开函数?
字典是什么?
b=a 复制列表吗?
没有显式 return 时返回什么?
具体异常处理应放在哪里?
答案表
- A — 相等比较用 ==。
- B — return 返回结果并结束调用。
- C — 记录可使用命名键。
- A — 它共享引用。
- B — 打印不会自动成为返回值。
- C — 保留诊断信息,处理预期失败。
引导阅读
- Python 控制流 — 阅读函数与参数传递,跟踪局部名称。
- Python 数据结构 — 阅读列表、字典与推导式,把筛选改写为 for 循环。
复习与下一步
不看代码解释目录的输入验证、列表表示与返回约定,增加一个失败输入测试。模块 04 将介绍论证程序所需的数学语言。
关键术语
| 术语 | 含义 |
|---|---|
| 修改 | 改变现有对象状态。 |
| 别名 | 多个引用指向同一对象。 |
| 异常 | 中断正常控制流的信号。 |