跳到主要内容

为什么是 Python,以及怎么使唤它

这一章讲三件事: 一门明明很慢的语言凭什么当了 AI 的门面; 拿到一个问题该从哪儿下手(两把思维工具);以及第 01 章那条链的最后一环 —— 一个 −1 到 1 的数,怎么真的变成两个轮子的转速。 它在全书链条里的位置是第 1 级台阶: 要让车自己跑,先得能指挥计算机。 不需要编程基础,遇到的生词都在当场解释。

1. 顶层全景

一个问题(「电池 11.5V,这车能上场吗?」)

│ ① 用两把工具拆开它:计算思维(把实际问题变成能算的东西)
│ IPO(输入什么 — 怎么处理 — 输出什么)

一段 Python 代码

│ ② 交给「解释器」——它先把代码译成一种中间形式,再一条条执行

结果打印在屏幕上

│ ③ 真正费算力的活(几百万次乘加)不在这一层做,
│ Python 把它们转手交给用 C 写好的库



图说:这一章从上往下走一遍。第 2 节讲最下面那一格(为什么慢却好用),
第 3 节讲最上面那一格(两把工具),第 4—7 节讲中间那一格(语法零件)。

本章主走查: 「电池电压 11.5V,这辆车该不该上场?」 这个问题会从第 4 节一路走到第 7 节,每一节给它加一个零件。 另有一处副走查在第 5 节 —— 那是第 01 章那条链的最后一环,不在主走查上,所以单独走。

2. 一门慢语言,凭什么当了 AI 的门面

先看现象:程序是怎么变成机器动作的

计算机真正能直接执行的,只有一长串 0 和 1 —— 书里管这个叫机器语言。 比如在一台 16 位计算机上,「把 2 和 3 加起来」这条指令长这样:11010010 001110111

没人愿意这样写程序。 所以有了一层一层的翻译:

层次长什么样谁能读
机器语言11010010 00111011只有 CPU
汇编语言add 2, 3, result人勉强能读,和机器指令一一对应
高级语言result = 2 + 3人一眼能读,和具体机器无关

书把前两种叫低级语言,第三种叫高级语言。「低」不是贬义, 它指的是离硬件近:直接摸得到内存地址和寄存器,代价是换一台不同架构的机器就跑不了2

高级语言怎么变回机器认得的东西:两条路

编译执行:整份代码 → (编译器一次翻译完) → 一个可执行文件 → 直接跑
快;但换个平台要重新翻译一遍。C、C++、Java 走这条

解释执行:代码 → (解释器一行一行翻译,翻一行跑一行)
慢;但换个平台不用改。Python、JavaScript、Ruby 走这条

图说:一个是「先全部译成中文再读」,一个是「读一句译一句」。
后者每次读都要重译,所以慢。

Python 走的其实是混合路。 书自己纠正了「Python 是纯解释型」这个流行说法: 它运行时会先把代码转换成中间形式的字节码,再由解释器执行这些字节码3

「字节码」在这里当场解释: 它是一种介于人写的代码和机器指令之间的东西 —— 比源代码更接近机器、但还不是任何一台具体机器的指令。好处是只用翻译一次, 之后重复执行就省下了反复翻译的开销;坏处是它终究还要有人边读边执行, 所以还是比直接跑机器码慢。

那为什么做 AI 反而都用它

这是本节的核心问题。答案不是「它其实不慢」,答案是「慢的那一层没在干活」。

书给的说法很直接:因为 Python 编程方式灵活简单,很多用 C、C++ 开发的专业库 都可以通过简单的接口封装以供 Python 使用,所以 Python 被称为**「胶水语言」**4

拆开看这件事:

你写的 Python: result = numpy.dot(A, B) ← 一行,慢的那一层只执行了这一行


实际发生的: 一段用 C 写好、编译成机器码的矩阵乘法
几百万次乘加,全速跑


还给你: 结果

图说:Python 在这里只做了「点菜」,炒菜的是 C。
点菜慢一点无所谓,因为炒菜才是耗时间的那部分。

这就是全书的技术前提。 后面所有「把 128×128 的图送进网络算一遍」这类动作, Python 只负责发号施令,真正的算术在别人写好的库里跑。

生态:为什么随手就有库可用

书还给了三个数字,说明这门语言的可用零件有多少5:

数量参照
标准库(装好就有,不用另外装)270 个相当于买手机时预装的应用
第三方库(要另外装)十几万个相当于整个应用商店
装一个第三方库要几步一条命令pip install 名字

书还点出了这类开源生态的三个特点:竞争发展(同一个功能常常有好几个项目在抢, 赢者通吃)、相互依存(库和库互相调用)、迅速更迭 —— 活跃项目的更新周期常常不到一个月,而传统商业软件是 3 到 6 个月6

判断(我们的,不是书里的): 「更新周期不到一个月」在 2024 年是优点, 在工程上却是一把双刃剑 —— 第 14 章和第 16 章各有一处是被它咬到的: 装框架必须找和硬件系统版本对应的那个包,版本对不上就装不上。 在这件事上是互斥的。 如果错,会错在: 如果那两处装不上其实是硬件厂商发布节奏的问题、而不是开源生态更新快, 那这条因果就挂错了地方。判据是:同一块板子换个非开源的工具链,会不会也有版本对不上的问题。

3. 拿到一个问题,从哪儿下手

这一节给两把工具。它们贯穿全书 —— 后面每一个实例都是照这两把工具拆开的。

工具一:计算思维

这个词由周以真在 2006 年的一篇论文里提出7它不是「像计算机那样思考」, 恰恰相反 —— 书特意强调它是求解问题的一种途径。

它的两个核心特征是抽象自动化,四个步骤是:

① 把实际问题抽象成数学问题,建一个模型
② 把模型里的变量和规则用符号表示出来
③ 把解题思路写成一步步的算法
④ 让计算机去执行

图说:书对这四步的总结值得记住——
「抽象是方法和手段,自动化是最终的目标」。
抽象贯穿全程,自动化是为了把人从重复计算里解放出来。

书还给「计算」下了一个很宽的定义:用特定的符号串,按照预定的规则, 经过有限步骤,得到一个满足预定条件的符号串8这个定义的用处是:它把「什么能算」的边界推得很远 —— 只要能符号化、能定规则, 就能算。识别一张图属于哪一类,按这个定义也是「算」。

工具二:IPO

比上面那把更小、更实用。IPO 就是三个英文单词的首字母:输入 — 处理 — 输出9

字母意思这本书里通常是什么
Input数据从哪儿来键盘、文件、摄像头、别的程序
Process拿它干什么书说这一部分统称算法,是程序的灵魂
Output结果怎么给出去屏幕、文件、另一个程序、电机

拿到任何一个题,先填这三个格子。 下面两节各拆一个实例,两次都是照这个格子填的。

4. 第一个实例:一个到处都是的分段函数

书的第一个例子不是「Hello World」,而是本行的东西 —— 这是它的一个特点。

先看这个函数在做什么

规则只有一句:输入大于 0,就原样输出;输入是 0 或者更小,就输出 0。

输入 x = 3.7 → 输出 3.7
输入 x = 0 → 输出 0
输入 x = −2.1 → 输出 0

图说:正数照单全收,负数一律压成 0。就这么简单。

用 IPO 拆开它:输入是一个数 x;处理是那句判断;输出是处理后的数。

示范代码(这段是我们写的,不是书里的 —— 原书的代码是图片,清洗出来的文本里没有):

def relu(x):
if x > 0:
return x
else:
return 0

现在给它留名

这个分段函数在深度学习里到处都是。它的名字叫 ReLU —— 全称是 Rectified Linear Unit,书直接说它「实际上是斜坡函数,即 f(x) = max(0, x)」10

它属于一类东西,这类东西叫激活函数。书给的定位是:它最终决定要发送给下一个神经元的信息11

书还说这类函数是为了实现「非线性输出」。非线性 = 画出来不是一条直线 —— 画出来是直线的那种叫线性(比如 y = 2x + 1),而上面这个函数在原点拐了个弯,所以它是非线性的。

现在你只需要记住这两个名字和这条规则。 为什么神经网络里非要有这么一道手续、为什么偏偏是这个形状最常用, 第 07 章讲(那里会看到它是被另一个更早的做法逼出来的)。

为什么要在这里就给名字,而不是留到第 07 章: 因为你翻开任何一个深度学习工具的文档,relu 这个词都会在第一页出现。 现在给了名字,你以后撞见它时能认出「这就是我已经懂了的那个东西」。

5. 第二个实例:那个数怎么变成两个轮子的转速

这是第 01 章那条链的最后一环。书自己说,第 2 章的语法元素全部是通过这个实例讲的。

先回到车上

第 01 章说过:这车没有方向盘,四个电机一个轮子一个,转向靠前面两个轮子转得不一样快。 所以模型吐出来的那个 −1 到 1 的数,必须先翻译成两个轮子各自的转速。

书给的规则只有两句12:

转角的值怎么办
大于 0(右转)右轮减速,左轮速度不变
小于 0(左转)左轮减速,右轮速度不变
等于 0两轮同速,直行

副走查:−0.4 进来,两个转速出去

输入 转角 = −0.4 基础速度 = 60(两轮都是)


处理 −0.4 < 0 ⇒ 左转 ⇒ 左轮减速、右轮不变
减多少?按转角的绝对值成比例:0.4 × 60 = 24,从左轮里扣掉


输出 左轮 = 60 − 24 = 36 右轮 = 60

图说:车左边的轮子慢了,右边的没变,车就绕着左边偏过去了。
**基础速度 60 和「按绝对值成比例」这条折算规则是我们为演示补的**——
书只给了「谁减速、谁不变」,没给减多少。

示范代码(我们写的):

angle = eval(input("转角(-1 到 1):")) # 从键盘读一个数
base = 60 # 基础速度

if angle > 0: # 右转
left, right = base, base * (1 - angle)
elif angle < 0: # 左转
left, right = base * (1 + angle), base
else: # 直行
left, right = base, base

print("左轮 {:.0f},右轮 {:.0f}".format(left, right))

这段代码里有本章后面要讲的全部零件: 读输入、把字符串(一串字符 —— 你敲进去的 -0.4 在程序眼里先是四个字符,不是一个数)变成数、三个分支、格式化输出。 下面四节把它们逐个拆开。

第 01 章那条主走查的最后一步,到这里兑现了。 这也是这本书的一个特点:难的那一段在中间,两头都很朴素。

6. 最小的语法零件

这一节把上面那段代码里的零件逐个交代。

缩进不是排版,是语法

Python 用每行前面的空白来表示代码之间的包含关系,不用大括号13。 上面代码里 if 下面那一行往里缩了四格,意思就是「这一行属于这个 if」。

缩进不一致会直接报错或者算出错误结果。 常用四个空格或一个 Tab,两者不混用。

标识符:给东西起名字

变量(一个能装值、而且值可以随时换掉的名字)、函数、类的名字统称标识符。规则是:字母、数字、下划线组成,不能以数字开头, 中间不能有空格,区分大小写(pyPy 是两个不同的变量)14

一个有意思的细节:Python 3 里中文可以当变量名。 书直接给了例子: 智能车python智能车 都是合法的名字。(能用不等于该用 —— 这是我们的提醒,不是书的。)

赋值:等号不是「等于」

speed = 60 读作「把 60 装进 speed 里」,不是「speed 等于 60」。 判断相等要用两个等号 ==15

Python 还允许一次给多个变量赋值:left, right = 36, 60。 它的执行顺序是先把右边全部算出来,再一起赋给左边 —— 所以 x, y = y, x 能一句话交换两个变量的值,不需要中间变量。

三个内置函数:input、print、eval

函数干什么一个坑
input()从键盘读一行不管你敲什么,它都当字符串还给你。敲 11.5 得到的是四个字符,不是一个数
print()往屏幕输出要控制小数位数得用格式化写法,比如 "{:.2f}".format(x)
eval()把一个字符串当成 Python 表达式算一遍见下,它很危险

因为 input() 只给字符串,所以要拿它做算术就得配 eval(): eval(input()) 这个组合书里反复在用16

eval() 有安全隐患,书专门点了名。 原因很直白: 它会把用户敲进来的任何东西当代码执行。2+3 它算出 5; 敲一个删文件的表达式,它也照办。书举的例子温和一些:直接敲 py, eval 会把引号去掉、把 py 当成一个变量名,而这个变量没定义过,于是报错17

这一条今天更要紧了(补充,不在书里,来自通用知识): 只要那串字符有可能来自别人 —— 网络请求、配置文件、外部数据集 —— 就不该用 eval。要把字符串变成数,用 int()float(),它们只做类型转换、不执行代码。

注释与库引用

# 后面的内容解释器一概忽略;三个引号包起来的一段也一样18。 要用别人写好的功能,用 import 库名 引进来 —— 这一句是后面每一章的开头第一行19

7. 主走查:「电池 11.5V,这车能上场吗」

这一节是本章的主走查,前面所有零件都在它上面各占一步。

先看现场

书给了这个实例的真实来历,值得原样记住:

2023 年智能车大赛前一晚,某学生给电池充了一整晚的电; 第二天参加比赛的时候,小车跑得出乎意料的慢20

充满电反而更慢,这不符合直觉。 书给的解释是电压过高 —— 比赛用的镍氢电池 电压范围是 8 到 16V,而车上处理单元的工作电压只有 10 到 13V21。 充过头,电压顶出了工作区间。

8V ─────┬──────────────┬───── 16V ← 电池能到的范围
│ │
10V 13V ← 车能正常工作的范围
↑ ↑ ↑
太低 正常 太高
(电压不足) (超出工作电压)

图说:电池的量程比车能接受的范围宽得多,两头都会出事。
所以「开机前先量一下电压」是一道必要工序,不是多余的谨慎。

走查:11.5V 进来,一句结论出去

① 读进来 input("电压:") → 用户敲 11.5 → 拿到字符串 "11.5"
↑ 注意:是四个字符,不是一个数

② 变成数 eval("11.5") → 11.5(浮点数)

③ 分三支判 11.5 < 10 ? 否
11.5 > 13 ? 否
都不是 ⇒ 落到 else 这一支

④ 输出 print(...) → 「电压 11.50V,正常,可以上场」

示范代码(我们写的):

v = eval(input("电池电压(V):"))

if v < 10:
print("电压 {:.2f}V,过低,充电后再上场".format(v))
elif v > 13:
print("电压 {:.2f}V,过高,放一会儿电再上场".format(v))
else:
print("电压 {:.2f}V,正常,可以上场".format(v))

加上循环:连读五次取平均

一次读数可能是抖的。改成连读五次求平均,就要用到循环。

Python 的循环分两种,判据是「次数定不定得下来」22:

用什么什么时候用
次数确定for「读五次」「把这个列表里每个元素处理一遍」
次数不确定while「一直读到电压稳定为止」

示范代码(我们写的):

total = 0
for i in range(5): # 确定循环五次
total = total + eval(input("第 {} 次读数:".format(i + 1)))
print("平均电压 {:.2f}V".format(total / 5))

走查一遍(这五个读数是为演示编的): 读到 11.4、11.6、11.5、11.5、11.5 → 累加得 57.5 → 除以 5 → 11.50V

循环里的两个零件,和一个容易踩的坑

  • break:立即跳出循环。 坑在这里 —— 如果有好几层循环套着, break 只跳出最里面那一层,外面那层照跑23;
  • continue:跳过本次剩下的部分,直接进入下一次;
  • for/while 后面都可以跟一个 else它只在循环「正常跑完」时才执行; 一旦被 break 打断,这个 else 就不执行24

for-else 这个搭配在别的语言里少见,用处是「找了一圈没找到」: 循环里找到就 break,else 里写「没找到」的处理。

8. 让程序别一出事就崩

这一节讲的东西,后面每一次读数据文件都会用到。

现象先行

你的程序要读一个数据文件。文件不在、被别人占用、路径写错 —— 这些都会发生, 而默认行为是程序当场崩掉,后面的代码一行都不跑。

如果这是训练脚本跑到第 200 轮时发生的,你就白跑了两个小时。

做法:把可能出事的那几行圈起来

Python 用 try...except:把有风险的代码放进 try, 出事之后要做什么放进 except25

try:
f = open("data/train.txt", "r")
lines = f.readlines()
f.close()
except FileNotFoundError:
print("训练列表不存在,先跑一次数据集切分")
lines = []

书还给了另外两个搭配26:

关键字什么时候执行
else没出事的时候才执行
finally不管出没出事都执行 —— 用来做「无论如何都要关掉文件」这类收尾

这里有一条判据值得写死(我们的,不是书里的): try 是用来接住你预料得到、而且知道该怎么办的意外(文件不在、用户输入了字母)。 它不是用来盖住真正的 bug 的。 如果错,会错在: 如果某段代码的失败原因你根本分不清是意外还是 bug, 那这条判据就用不上,只能先让它崩、看清堆栈再说。

9. 「随机」其实一点都不随机

这一节的知识点后面只用一次,但那一次很要紧:切数据集的时候。

现象先行

第 03 章会讲到:切训练集之前必须先把数据打乱。 问题来了 —— 打乱之后,这次实验和上次实验用的就不是同一批数据了,结果没法对比

做法:它本来就是算出来的

书说得很直接:这些数不是真正的随机数,而是通过特定算法生成的, 所以叫伪随机数。用的算法叫梅森旋转,产生 53 位精度的浮点数, 周期是 2¹⁹⁹³⁷ − 127

这个周期数要有个参照物: 它的意思是「这串数要走这么多个之后才会开始重复」。 而可观测宇宙里的原子总数大约是 10 的 80 次方 —— 2¹⁹⁹³⁷ 比它大得离谱, 所以「重复」这件事在实践中永远不会发生。

书还诚实地写了它的边界:正因为完全确定性(每一步都是照固定规则算出来的,没有半点真随机),它 「完全不适用于加密目的28。 (补充,不在书里,来自通用知识:原因是只要看到足够多的输出,就能反推出内部状态, 接下来的每一个数都能被算出来。)

用处:种子

既然是算出来的,那就有个起点。这个起点叫种子: 只要种子相同,每次生成的随机数序列就完全相同29

import random
random.seed(42) # 定下起点
random.shuffle(data) # 打乱——但每次运行打乱的结果都一样

这就是「打乱了还能复现」的全部原理。 第 03 章切数据集、 第 13 章按 8:2 分训练验证集,靠的都是它。

10. 作者的判断与证据

说法是哪一类
Python 先编成字节码再解释执行有证据: 这是语言实现的事实,书用它纠正了「纯解释型」的说法
标准库约 270 个、第三方库十几万个有证据,但是快照。 这是 2024 年的量级,今天只多不少
「活跃开源项目更新周期少于一个月」作者的观察,没给数据来源。 方向没错,具体数字别当精确统计引
「胶水语言」是 Python 成为 AI 门面的原因作者的判断,而且我们认为它站得住 —— 全书后面每一次调用都在印证它
电池实例的来历(赛前充一整夜)作者的现场经验,书明写是「实例设计来源」,这是全书少有的带现场的段落
Python 3.10 起有一种新的多分支写法,书明说不讲有证据: 书自己划的范围30。这属于「书里说不知道 / 不讲」的坦白,照实写

11. 边界与局限

  • 这一章合并了原书四处内容: 第 1 章的语言分类、第 2 章的语法元素、第 3 章的控制结构、 第 7 章的计算生态。原书把「语言分类」放第 1 章、「为什么用 Python」放第 7 章,中间隔了五章 —— 其实是同一件事,合并讲最省力。
  • 书里所有代码都是图片。 本章出现的每一段代码都是我们自己写的, 照书的文字描述复现,不是原书代码。
  • 手册式的内容我们整体不采用(那种一条条列出「这个函数怎么调、有哪些参数」的表格, 行话叫 API 文档):math 库 44 个函数、time 库 12 个函数、 turtle 库的函数清单、字符串 43 种方法。这些在原书里本来就是图片,而且属于「查文档就有」。
  • turtle 画图那一节我们跳过了。 它在原书里占了不小篇幅(还有一个画赛道的实例), 但和主线没有关系;唯一有价值的那个点 ——「不改代码、只改数据文件就画出另一条赛道」 —— 我们挪到第 03 章讲。
  • 递归(函数自己调用自己)和汉诺塔那道经典题也跳过了。 全书后面一次都没再用到。
  • eval 的危险性书只点了一句。 今天这件事的分量比 2024 年更重,我们补了一段。

12. 可带走的

全章主走查一行写完: 键盘敲入 11.5input() 拿到字符串 "11.5"eval() 变成数 11.5 → 三分支比对 10—13V 的工作区间 → 落到 else → 打印「电压 11.50V,正常,可以上场」;改成 for 连读五次(11.4 / 11.6 / 11.5 / 11.5 / 11.5) → 累加 57.5 → 平均 11.50V那五个读数是为演示编的,不是书里的数。

  1. 低级语言离硬件近、换机器就跑不了;高级语言离人近、要靠翻译才能跑;
  2. Python 走混合路:先编成字节码,再解释执行 —— 所以它比 C 慢,但比纯逐行解释快;
  3. 它慢却当家,是因为费算力的那部分根本不在它这一层跑 —— C/C++ 写好的库封装成简单接口给它调,它只是黏合剂(「胶水语言」);
  4. 一条命令就能装一个库,能装的有十几万个 —— 这才是它的真正护城河;
  5. 拿到问题先填三个格子:输入什么 — 怎么处理 — 输出什么(IPO);
  6. ReLU 就是「大于 0 原样输出,否则输出 0」,它属于一类叫激活函数的东西 —— 为什么非要有它,第 07 章讲;
  7. 一个 [−1,1] 的转角变成轮速只有一句判断: 右转就右轮减速、左轮不变 —— 第 01 章那条链的最后一环,就这么简单;
  8. input() 永远给你字符串;eval() 能把字符串当代码执行,所以方便,也所以危险;
  9. 缩进是语法不是排版;break 只跳出最里面那一层循环; for/while 后面的 else 只在没被 break 打断时才执行;
  10. 随机数是算出来的,给定同一个种子就给出同一串数 —— 这是后面「打乱了数据集还能复现实验」的全部原理。

13. 原文地图

主题原书章原文位置
低级 / 高级语言、机器语言与汇编的例子第1章 绪论text/02-ch01.txt:195(搜「低级语言和高级语言」) · text/02-ch01.txt:205(搜「11010010」) · text/02-ch01.txt:209(搜「add 2, 3, result」)
编译执行与解释执行;Python 的混合模式与字节码第1章 绪论text/02-ch01.txt:219(搜「编译执行」) · text/02-ch01.txt:223(搜「逐行被解释器读取」) · text/02-ch01.txt:225(搜「中间形式的字节码」)
Python 的诞生与特点第1章 绪论text/02-ch01.txt:237(搜「Guido van Rossum」)
前 6 章用 IDLE、第 7 章起用 Jupyter第1章 绪论text/02-ch01.txt:261(搜「第7章往后」)
计算生态三特点;胶水语言;模块/包/库第7章 Python计算生态及机器学习概述text/08-ch07-7-python.txt:45(搜「竞争发展」) · text/08-ch07-7-python.txt:53(搜「胶水语言」) · text/08-ch07-7-python.txt:57(搜「模块(Module)」)
标准库约 270 个;pip 安装第7章 Python计算生态及机器学习概述text/08-ch07-7-python.txt:67(搜「270个左右」) · text/08-ch07-7-python.txt:73(搜「pip是一个」)
计算思维:周以真、抽象与自动化、四步、计算的本质第7章 Python计算生态及机器学习概述text/08-ch07-7-python.txt:13(搜「周以真」) · text/08-ch07-7-python.txt:23(搜「抽象(Abstraction)」) · text/08-ch07-7-python.txt:33(搜「抽象是方法和手段」) · text/08-ch07-7-python.txt:35(搜「有限步的步骤」)
IPO 三步第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:19(搜「IPO代表着」) · text/03-ch02-2-python.txt:23(搜「算法是程序最重要的部分」)
激活函数的定义;ReLU 的定义第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:31(搜「激活函数(Activation Function)」) · text/03-ch02-2-python.txt:33(搜「Rectified Linear Unit」)
差速转向实例第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:39(搜「右轮减速」)
注释、缩进、标识符、赋值、input、print、eval、库引用第2章 Python基本语法元素及数据类型text/03-ch02-2-python.txt:51(搜「单行注释」) · text/03-ch02-2-python.txt:71(搜「使用缩进来表示代码块」) · text/03-ch02-2-python.txt:81(搜「智能车」) · text/03-ch02-2-python.txt:99(搜「同步赋值语句」) · text/03-ch02-2-python.txt:107(搜「从控制台获得用户输入」) · text/03-ch02-2-python.txt:137(搜「安全隐患」) · text/03-ch02-2-python.txt:147(搜「import保留字」)
三种控制结构第3章 程序控制结构text/04-ch03.txt:25(搜「顺序结构、分支结构和循环结构」)
电池电压实例与它的现场来历第3章 程序控制结构text/04-ch03.txt:53(搜「镍氢电池」) · text/04-ch03.txt:55(搜「充了一整晚」)
确定次数循环 vs 非确定次数循环第3章 程序控制结构text/04-ch03.txt:87(搜「确定次数循环」)
break 只跳最内层;else 只在正常结束时执行第3章 程序控制结构text/04-ch03.txt:129(搜「只跳出最内层循环」) · text/04-ch03.txt:133(搜「循环正常结束」)
异常处理 try / except / else / finally第3章 程序控制结构text/04-ch03.txt:145(搜「try...except语句」) · text/04-ch03.txt:151(搜「finally子句」)
梅森旋转、周期、不适用于加密;随机数种子第3章 程序控制结构text/04-ch03.txt:161(搜「梅森旋转算法」) · text/04-ch03.txt:165(搜「不适用于加密目的」) · text/04-ch03.txt:177(搜「随机数种子」)
Python 3.10 的新分支写法,书明说不讲第3章 程序控制结构text/04-ch03.txt:75(搜「match...case」)

Footnotes

  1. 出处:「第1章 绪论」第 205 段(text/02-ch01.txt:205,搜「11010010」)。原文给的例子是「执行数字 2 和 3 的加法,16 位计算机上的机器指令为 11010010 00111011」,并说明不同计算机结构的机器指令会有所不同。

  2. 出处:「第1章 绪论」第 201 段(text/02-ch01.txt:201,搜「低级语言直接与计算机硬件交互」)与第 209 段(text/02-ch01.txt:209,搜「add 2, 3, result」)、第 213 段(text/02-ch01.txt:213,搜「result=2+3」)。

  3. 出处:「第1章 绪论」第 225 段(text/02-ch01.txt:225,搜「中间形式的字节码」)。原文:「现实中很多高级语言的执行方式不是绝对的,而是综合使用了解释执行和编译执行的混合模式」。补充(不在书里,来自通用知识):字节码之所以能省时间,是因为源代码只需要被翻译一次,之后重复执行时直接跑字节码。

  4. 出处:「第7章 Python计算生态及机器学习概述」第 53 段(text/08-ch07-7-python.txt:53,搜「胶水语言」)。原文:很多采用 C、C++ 等语言开发的专业库都可以通过简单的接口封装以供 Python 使用,这种黏性使 Python 逐渐成为各类编程语言之间的接口语言。

  5. 出处:「第7章 Python计算生态及机器学习概述」第 67 段(text/08-ch07-7-python.txt:67,搜「270个左右」)、第 53 段(text/08-ch07-7-python.txt:53,搜「十几万个第三方库」)、第 73 段(text/08-ch07-7-python.txt:73,搜「pip是一个」)。

  6. 出处:「第7章 Python计算生态及机器学习概述」第 45—49 段(text/08-ch07-7-python.txt:45,搜「竞争发展」;text/08-ch07-7-python.txt:49,搜「3~6个月」)。

  7. 出处:「第7章 Python计算生态及机器学习概述」第 13 段(text/08-ch07-7-python.txt:13,搜「周以真」)。原文说明这一概念由时任卡内基梅隆大学计算机系主任周以真教授于 2006 年在论文中提出;第 19 段(text/08-ch07-7-python.txt:19,搜「它是人类的思维方式」)强调它是人的思维方式,不是计算机的。

  8. 出处:「第7章 Python计算生态及机器学习概述」第 33 段(text/08-ch07-7-python.txt:33,搜「抽象是方法和手段」)与第 35 段(text/08-ch07-7-python.txt:35,搜「有限步的步骤」)。四个步骤见第 25—31 段。

  9. 出处:「第2章 Python基本语法元素及数据类型」第 19—27 段(text/03-ch02-2-python.txt:19,搜「IPO代表着」;text/03-ch02-2-python.txt:23,搜「算法是程序最重要的部分」)。

  10. 出处:「第2章 Python基本语法元素及数据类型」第 33 段(text/03-ch02-2-python.txt:33,搜「Rectified Linear Unit」)。原文:它「实际上是斜坡函数,即 f(x)=max(0,x)」,如果输入大于 0 就直接返回输入值,如果输入是 0 或更小则返回 0。原书紧接着给的代码是一张图片,清洗文本里没有,所以本节的示范代码是我们写的。

  11. 出处:「第2章 Python基本语法元素及数据类型」第 31 段(text/03-ch02-2-python.txt:31,搜「激活函数(Activation Function)」)。原文:激活函数「旨在实现神经网络模型的非线性输出」,并且「最终决定了要发送给下一个神经元的信息」。这两个名字书在第 2 章就给了,但要到第 8 章才回答「为什么」——我们把「为什么」放在第 07 章。

  12. 出处:「第2章 Python基本语法元素及数据类型」第 39 段(text/03-ch02-2-python.txt:39,搜「右轮减速」)。原文说明这个例子「体现了 IPO 程序设计思想,同时也体现了 Python 的大部分基本语法元素」。基础速度 60 与「按转角绝对值成比例减速」这条折算规则书里没有,是我们为演示补的。

  13. 出处:「第2章 Python基本语法元素及数据类型」第 71 段(text/03-ch02-2-python.txt:71,搜「使用缩进来表示代码块」)与第 73 段(text/03-ch02-2-python.txt:73,搜「缩进不一致」)。

  14. 出处:「第2章 Python基本语法元素及数据类型」第 81 段(text/03-ch02-2-python.txt:81,搜「智能车」)。原文给的合法标识符例子包括 python_smart_car智能车python智能车

  15. 出处:「第2章 Python基本语法元素及数据类型」第 95 段(text/03-ch02-2-python.txt:95,搜「赋值运算符」)与第 99 段(text/03-ch02-2-python.txt:99,搜「同步赋值语句」)。「= 是赋值、== 是等于」见「第3章 程序控制结构」第 49 段(text/04-ch03.txt:49,搜「表示等于」)。

  16. 出处:「第2章 Python基本语法元素及数据类型」第 113 段(text/03-ch02-2-python.txt:113,搜「默认返回一个字符串」)与第 139 段(text/03-ch02-2-python.txt:139,搜「eval(input())」)。

  17. 出处:「第2章 Python基本语法元素及数据类型」第 137 段(text/03-ch02-2-python.txt:137,搜「安全隐患」)。原文给的例子是:直接输入字符串 "py",eval 会把引号去掉、把 py 解析为变量,由于之前未定义 py 变量,解释器会报错。

  18. 出处:「第2章 Python基本语法元素及数据类型」第 49—55 段(text/03-ch02-2-python.txt:51,搜「单行注释」)。

  19. 出处:「第2章 Python基本语法元素及数据类型」第 147 段(text/03-ch02-2-python.txt:147,搜「import保留字」)。

  20. 出处:「第3章 程序控制结构」第 55 段(text/04-ch03.txt:55,搜「充了一整晚」)。原文明写这是「实例设计来源」,并且承认「当然也可能是其他原因造成的,但是赛前检查电池电压是非常重要的」——这句保留意见值得照实转述。

  21. 出处:「第3章 程序控制结构」第 53 段(text/04-ch03.txt:53,搜「镍氢电池」)。原文:比赛中使用的镍氢电池电压范围为 8~16V,而智能车微处理单元的工作电压为 10~13V,实际使用中电池电压由电压读取电路获得。

  22. 出处:「第3章 程序控制结构」第 87—91 段(text/04-ch03.txt:87,搜「确定次数循环」)。

  23. 出处:「第3章 程序控制结构」第 129 段(text/04-ch03.txt:129,搜「只跳出最内层循环」)。

  24. 出处:「第3章 程序控制结构」第 133 段(text/04-ch03.txt:133,搜「循环正常结束」)与第 105 段(text/04-ch03.txt:105,搜「遇到了break语句」)。

  25. 出处:「第3章 程序控制结构」第 145 段(text/04-ch03.txt:145,搜「try...except语句」)。原文的定位是:异常处理让程序「在遇到错误时采取适当的措施,而不是直接崩溃」。

  26. 出处:「第3章 程序控制结构」第 149—151 段(text/04-ch03.txt:151,搜「finally子句」)。

  27. 出处:「第3章 程序控制结构」第 161 段(text/04-ch03.txt:161,搜「梅森旋转算法」)与第 165 段(text/04-ch03.txt:165,搜「53位精度」)。补充(不在书里,来自通用知识):可观测宇宙的原子总数常被估在 10 的 80 次方量级,用来给这个周期一个参照物。

  28. 出处:「第3章 程序控制结构」第 165 段(text/04-ch03.txt:165,搜「不适用于加密目的」)。原文只给结论没给理由,「可以从有限输出反推内部状态」这句是我们补的通用知识。

  29. 出处:「第3章 程序控制结构」第 177 段(text/04-ch03.txt:177,搜「随机数种子」)。原文:「只要种子相同,每次生成的随机数序列也相同。这种情况便于测试和同步数据。」

  30. 出处:「第3章 程序控制结构」第 75 段(text/04-ch03.txt:75,搜「match...case」)。原文:「Python 3.10 增加了 match...case 的条件判断,这里不做详细介绍,有兴趣的同学可以自学。」