编程语言研究书库

三个案例 — 把前五章缝在一起

三个案例 — 把前五章缝在一起

这一章没有新概念,只有三道应用题。 前五章学的是零件,这一章把零件 装成三台小机器:超市收银、聚餐分账、复利计算器。读完你会形成一个重要认识: 入门阶段的程序,长得都很像。

1. 这一章在全书链条里的位置

这是第一部分的收官章。原书在前言里说过,案例的作用是「把小块知识组合起来, 展示怎么用它们解决真实问题」1——如果说第 02–05 章是体检的每一项指标, 这一章就是综合体检。它同时是第二部分(流程控制)的入口:file 末尾的部分导读 预告了接下来的主题——分支、循环、函数2。

2. 三个案例共用的骨架

把三个程序的代码并排摆开,会发现它们是同一个模子:

  ① 问数字        xxx = float(input('...')) 或 int(input('...'))
                    ——input 给字符串,转换器拆掉类型墙(第 02/03 章)
  ② 算            一行算式,把业务规则翻译成运算(第 04 章)
  ③ 打印          print(f'... ${结果:.2f}')
                    ——f-string 嵌值,:.2f 把金额钉在两位小数(第 05 章)

  图说:三个案例的差异全部集中在第 ② 步的那行算式上。

这一章真正的教学点就一个:业务规则怎么翻译成算式。下面逐台机器走一遍, 每一步都带原书给出的具体数字。

3. 案例一:收银找零(主线例子)

规则:顾客一单只买一种商品,不限量;税率 6.25%;先算含税总额,再问顾客付了多少, 找零3。

price    = float(input('What is the price per unit of the product? '))
quantity = int(input('What is the quantity of the product? '))
total    = price * quantity * (1 + 0.0625)
print(f'The total amount of this order with tax is ${total:.2f}')
paid     = float(input('What is the amount of bill paid? '))
change   = paid - total
print(f'The change is ${change:.2f}')

拿原书的演示输入走一遍(单价 25.99,数量 12,付款 350):

  ① price    = 25.99         (字符串 '25.99' → float 转换)
  ② quantity = 12            (字符串 '12' → int 转换)
  ③ 小计     = 25.99 × 12 = 311.88
  ④ 税       = 311.88 × 0.0625 = 19.4925
  ⑤ total    = 311.88 × 1.0625 = 331.3725 → 显示 $331.37(:.2f 四舍五入)
  ⑥ paid     = 350
  ⑦ change   = 350 - 331.3725 = 18.6275   → 显示 $18.63

  图说:算式 (1 + 0.0625) 是「含税价 = 原价 × 1.0625」的直译;
  显示值四舍五入、内部值不四舍五入——change 用的是 331.3725 不是 331.37。

两个细节值得停一秒:其一,1 + 0.0625 这种写法读业务规则的人一眼能认出 「加六个多点的税」;其二,第 ⑤⑦ 步的显示是 331.37 / 18.63,但第 ⑦ 步减法 用的是内部精确值——格式化只改显示,不改数值4。

4. 案例二:聚餐分账加小费

规则:饭前总额,税率 6.25%,小费 18%,人头数均摊5。

total = float(input('What is the total amount of the meal before tax? '))
num   = int(input('How many people to split the tips? '))
tax   = 0.0625
tip   = 0.18
total_due = total * (1 + tax + tip)
each_due  = total_due / num
print(f'Total due is ${total_due:.2f}. Each due is ${each_due:.2f}')

原书输入:饭前 124 美元,5 人。走一遍:124 × 1.2425 = 154.07, 154.07 / 5 = 30.814 → 显示 Total due is $154.07. Each due is $30.816。

这一版比案例一多一个进步:税率和小费被起成了名字(tax = 0.0625), 而不是像案例一那样把 0.0625 裸写在算式里。名字化之后,算式 total * (1 + tax + tip) 读出来就是业务规则本身。这就是第 03 章 「名字要有描述性」惯例的实战回报7。

5. 案例三:复利计算器

规则:本金、年数、年利率(0.03 表示 3%),算到期总额8。

saving = float(input('What is the amount of saving right now? '))
years  = int(input('What is the number of years? '))
rate   = float(input('What is the interest rate per year? '))
total  = saving * (1 + rate) ** years
print(f'The total amount after these years is: ${total:.2f}')

原书输入:本金 100000,10 年,年利率 0.05。算式是复利公式 「本息 = 本金 × (1 + 利率)^年数」的直译,** 运算符第一次挑大梁(第 04 章的 5 ** 2 在这里变成了 1.05 ** 10)。结果 162889.46——十万本金以 5% 复利 滚十年,变成了约十六万三9。

  ① 1.05 ** 10 = 1.6288946…        (幂运算:十年增长因子)
  ② 100000 × 1.6288946… = 162889.46
  图说:(1 + rate) ** years 一个式子装下了整个复利公式。

6. 作者的判断与证据

  • 案例选择是精心校准过的:收银(加减乘)、分账(除)、复利(幂)——三个案例 恰好把第 04 章的算术运算符按难度递进全部用上,且都是「算钱」,对初学者 没有领域门槛。
  • 每个案例开头都明确标注输入类型要求(「it should be a float」)3, 这是把「input 返回字符串、必须转换」这条铁律制度化——案例不假设你已经 内化它,而是每次都示范。
  • 本章开头的免责声明很重要:「此刻先假设用户会乖乖按说明输入」10。 也就是不处理乱输入(字母当数字、负数数量)——这是诚实的教学取舍: 输入校验要等流程控制(第 07 章分支)才能讲,先把主干立起来。

7. 边界与局限

  • 没有校验,没有错误处理。 乱输入会 ValueError 崩掉;付款小于总额会 输出负数找零也不报警。书的立场是「先假设用户配合」,真正的防御要等第 07 章 之后的工具。
  • 金额用 float 算,有精度暗坑。 0.0625、18.6275 这类小数在二进制里 存不精确,:.2f 的四舍五入只是遮羞。真实金融系统用 decimal 模块—— 本书没提,入门阶段接受 float 的近似即可(第 05 章边界节预告过)。
  • 三个案例都是「一问一答一输出」的脚本形态,没有循环、没有分支—— 第二部分学完,同样的题目可以重写成「反复结账直到收工」的样子,那才是 真正的收银系统。

8. 可带走的

  1. 入门程序的统一骨架:问(input+转换)→ 算(一行算式)→ 秀(f-string + :.2f)。
  2. 业务规则翻译成算式,是本阶段的核心手艺(含税 × 1.0625、复利 × (1+r)^n)38。
  3. 常量起名字(tax、tip),算式就能读成人话7。
  4. :.2f 只改显示不改数值;内部计算用精确值4。
  5. 收银案例里「付款→找零」两步,是最小版本的「状态接着上一步走」。
  6. 学完第 07、08 章,值得回到这三个案例做升级版:加输入校验、循环结账。

9. 原文地图

主题原书章原文位置
案例的定位与输入假设CHAPTER 6: Case Studies of Python Fundamentalstext/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:9(搜「test your understanding」) · text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:13(搜「assume users will follow instructions」)
收银规则六条同上text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:24(搜「sales tax of 6.25%」)
收银代码与演示数字同上text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:31(搜「price per unit」) · text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:51(搜「25.99」)
分账规则与代码同上text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:60(搜「total amount of meal before tax」) · text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:83(搜「124」)
复利规则与代码同上text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:90(搜「amount saved right now」) · text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:110(搜「100000」)
第二部分导读(分支/循环/函数预告)同上text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:114(搜「Flow Control and Functions」)

Footnotes

  1. 出处:「Preface」第 53–54 段(text/08-fm-preface.txt:53,搜「Case studies combine」)。原文:「Case studies combine all the small ideas to show how you can use them to solve real-world problems.」 ↩

  2. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 114–133 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:114,搜「Flow Control and Functions」)。部分导读预告的分支、循环、函数主题,即第 07–10 章。 ↩

  3. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 19–27 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:19,搜「check-out system」;:24,搜「sales tax of 6.25%」)。六条规则逐字依据原文。 ↩ ↩2 ↩3

  4. 「格式化只改显示不改数值」是对 :.2f 机制的通用知识补充;演示中的输入输出(331.37、18.63)见原文第 51–55 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:51,搜「25.99」)。手算分解(311.88、19.4925、18.6275)是我们依据原书算式补的验算步骤。 ↩ ↩2

  5. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 59–65 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:63,搜「tip at 18%」)。规则逐字依据原文。 ↩

  6. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 83–85 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:83,搜「total amount of the meal before tax? 124」)。输入 124 / 5 人及输出 $154.07 / $30.81 逐字依据原文。 ↩

  7. 「tax/tip 名字化的进步」是我们的观察;代码本身见原文第 72–73 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:72,搜「Set the tax rate」)。 ↩ ↩2

  8. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 89–94 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:92,搜「interest rate (it should be」))。规则逐字依据原文。 ↩ ↩2

  9. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 110–113 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:110,搜「100000」)。输入 100000 / 10 年 / 0.05 及输出 162889.46 逐字依据原文。 ↩

  10. 出处:「CHAPTER 6: Case Studies of Python Fundamentals」第 13–14 段(text/15-ch06-chapter-6-case-studies-of-python-fundamentals.txt:13,搜「assume users will follow instructions」)。原文:「we can assume users will follow instructions carefully」。 ↩

On this page