📑 本页目录(点开跳转)
00 · 怎么用这份教程
⏱ 36 分钟 | ⭐ 这不是 Python 入门 —— 是「你已经会写了,但它还是会咬你」的那十个地方
🎯 一句话
站里其余 15 个板块讲的是「用 Python 表达一个想法」,这一套讲「Python 自己是怎么运作的」。 因为那些板块里每一次崩、每一次慢、每一次「我这能跑你那不能跑」,都不是模型的问题,是这一层的问题。
⏱ 先说清楚这套的章比站内其他板块长(普遍 50–120 分钟,站内其他板块的中位是 30)—— 因为每个知识点都带实跑代码和真实报错,压不下去。设计上就没打算让你一次读完: 超过 55 分钟的章在中间有 🛑 休息点,最长的几章有两个,停在那里下次接着读就行。 徽章是按 170 字/分钟实测校准的,宁可吓到你,也不骗你。
🧩 一、这一套是怎么立起来的
站内 15 个板块的导读章几乎都写着同一句话:「需要会写几十行 Python」。
然后就没有然后了。没有任何一个板块负责那几十行。于是出现这样的分布:
| 站内现状 | 具体是什么样 |
|---|---|
yield 出现 11 次 |
全在 SSE 流式输出里用,没有一处讲 yield 何时暂停、生成器为什么只能遍历一次 |
装饰器 出现 11 次 |
智能体工程教程 18 让你亲手造一个 @tool,而闭包、functools.wraps、inspect.signature 站内一处没讲 |
deepcopy 出现 1 次 |
强化学习基础 08 里 self.q_target = copy.deepcopy(net),⭐ 这一行写成 = net 会让 DQN 静默退化,不报错、loss 还在降、只是学不出来 |
GIL / multiprocessing / timeit / cProfile |
各出现 0 次 |
虚拟环境 / 深拷贝 / 可变默认参数 / pathlib |
各出现 0 次 |
⭐ 最能说明问题的一条:机器学习与深度学习基础 的 附录B-代码速查 有一整节叫「⚡ 提速」,给了混合精度、torch.compile、n_jobs=-1 三招 —— 却没有一行教你怎么测量。按它改完,你无法判断改对没有。
⭐ 立项判据不是「这些知识重要」,是「站内第 X 章第 Y 句依赖了它,而站内没人讲」。 后面每一章开头都会告诉你它接的是站内哪一句话。
🚦 二、三道自测题:先判断这套适不适合你
不用查资料,先在心里回答,再跑一遍。三题里错一题以上,这一套就是给你写的。
# 三道自测题:先猜,再跑
import threading, time
# ① 可变默认参数
def f(x, seen=[]):
seen.append(x)
return seen
print("①", f(1), f(2), f(3))
# ② 生成器只能走一次
g = (i * i for i in range(5))
print("②", sum(g), "然后再来一次:", sum(g))
# ③ 纯 Python 的 CPU 活,多线程比串行快吗
def burn(n=2_000_000):
s = 0.0
for i in range(n):
s += i * i
return s
t0 = time.perf_counter(); [burn() for _ in range(4)]
serial = time.perf_counter() - t0
t0 = time.perf_counter()
ts = [threading.Thread(target=burn) for _ in range(4)]
[t.start() for t in ts]; [t.join() for t in ts]
threaded = time.perf_counter() - t0
print("③ 串行 %.2f s | 4 线程 %.2f s" % (serial, threaded))
本机(8 核 Windows / CPython 3.13)实际输出:
操作步骤
- [1, 2, 3] [1, 2, 3] [1, 2, 3]
- 30 然后再来一次: 0
- 串行 0.80 s | 4 线程 0.81 s
| 题 | 大多数人的直觉 | 实际 | 讲在哪 |
|---|---|---|---|
| ① | [1] [2] [3] |
三次都是 [1, 2, 3],因为默认值只在定义函数那一刻造了一次 |
01 章 |
| ② | 两次都是 30 | 第二次是 0,⚠️ 而且不报错 | 02 章 |
| ③ | 4 线程快 3~4 倍 | 一模一样(0.80 vs 0.81) | 04 章 |
⚠️ 三题的共同点:都不报错。这正是这一层最贵的地方 —— 报错的 bug 会被你修掉,不报错的会一直待在那里。
🗺️ 三、章节地图(11 章)
| 章 | ⏱ | 它回答的问题 |
|---|---|---|
| 00 怎么用这份教程 | 36 | 你在读的这一章 |
| ⭐ 01 名字、对象和绑定 | 56 | a = b 到底复制了什么?为什么改一个另一个跟着变? |
| 02 生成器与惰性求值 | 74 | yield 是「返回」还是「暂停」?为什么生成器只能走一次? |
| 03 装饰器与上下文管理器 | 144 | @tool / @app.post / with open(...) 是怎么做到的? |
| ⭐ 04 GIL:为什么多线程救不了你 | 94 | 线程、进程、async 三个该选哪个?判据是什么? |
| ⭐ 05 怎么量:计时、剖析、内存 | 90 | 全站在教怎么提速,怎么知道快没快? |
| 06 类型标注是给工具看的 | 54 | 标注运行时不检查,那 FastAPI 和 @tool 是怎么用上它的? |
| 07 异常、traceback 和调试 | 74 | traceback 怎么读?except Exception: pass 到底吞掉了什么? |
| 08 环境、依赖和 import | 118 | 「我这能跑你那不能跑」的三个确定来源 |
| 09 容器、哈希与顺序 | 112 | x in 列表 写在循环里,能把 10 秒变成 40 分钟 |
| 10 编码、路径和文件 | 40 | open() 不写 encoding 时,用的是谁的编码? |
正文 10 章合计 856 分钟 ≈ 14.3 小时;含本章 892 分钟 ≈ 14.9 小时(章内有 🛑 断点,设计上就是分次读)。
章与章的依赖(不想全读时看这个):
| 想读 | 得先有 |
|---|---|
| 02 / 04 / 09 | ⭐ 01(「名字绑到对象」是这三章反复用到的同一个模型) |
| 03 | 02(@contextmanager 的骨架就是一个生成器) |
| 06 | 03(functools.wraps 不写,inspect.signature 读到的就是错的) |
| 其余各章 | 互相独立,可以单独读 |
📋 四、三条读法路线
⭐ 别按 01→10 顺着读,除非你就是想通读。按你现在遇到的问题挑一条:
路线 A |「线上崩了,我要能查」(约 288 分钟,分几次读)
07 异常与 traceback → 10 编码、路径和文件 → 01 名字与绑定 → 08 环境与 import
先学会读现场(07),再认出最高频的两类现场:编码炸掉(10)和「两个名字指着同一个对象」(01),最后是「换台机器就不行」(08)。
路线 B |「脚本太慢,我要它快起来」(约 370 分钟,分几次读)
⭐ 05 怎么量 → 04 GIL 与并发选择 → 02 生成器 → 09 容器与哈希
⚠️ 05 必须放第一个。不先量就改,你改的九成不是瓶颈 —— 05 章有个实跑例子:剖析器自己的开销会把两段代码的快慢顺序颠倒过来。
路线 C |「把一次性脚本变成别人能用的东西」(约 390 分钟,分几次读)
08 环境与依赖 → 06 类型标注 → 03 装饰器与上下文管理器 → 07 异常
别人能装上(08)→ 别人能看懂接口(06)→ 你能给它加横切能力(03)→ 出事时别人能查(07)。
🧯 五、四条分工线:什么归这里,什么不归
⭐ 越界就是重复内容,所以这几条写死在这里:
| 话题 | 归谁 | 为什么这么分 |
|---|---|---|
名字绑到对象(a = b、可变默认参数、copy / deepcopy、id()) |
⭐ 本板块 01 | 这是语言层面的对象模型 |
缓冲区被共享(view / stride / .copy()) |
NumPy 那一层 | 同样叫「共享」,但共享的是内存缓冲区不是名字,机制完全不同 |
| 谁负责释放(所有权 / RAII) | C++ 那一层 | Python 有 GC,这个问题在 Python 里不存在 |
计时 / 剖析方法论(timeit 取 min、预热、cProfile 怎么读) |
⭐ 本板块 05 | 全站 timeit / cProfile 命中 0,整块归这里,别处只引用 |
还有三处是站内已经讲透的,本板块只链过去不重做:
| 话题 | 已经讲在哪 | 本板块的边界 |
|---|---|---|
| async / 事件循环 | ⭐ AI全栈 03 · 后端骨架 第三节,带实跑对照 | 04 章 只讲「三种并发怎么选」和「线程什么时候有用」,不重讲 async 语法 |
| 结构化日志 | AI全栈 15 · 可观测性 | 07 章只讲异常机制与本地调试,不做日志体系 |
| pytest / 测不确定的系统 | AI全栈 15b · 怎么测不确定的系统 | 本板块不设测试章;07 只讲 assert 的语义坑 |
🛠️ 六、明确不讲什么
免得你翻半天找不到:
| 不讲 | 理由 |
|---|---|
语法入门(if / for / 函数怎么定义) |
这一套假定你已经会写了。⚠️ 判据不是「你学过多久」,是上面那三道自测题 |
| Web 框架用法(FastAPI 路由、Pydantic 模型) | AI全栈 整个板块在讲 |
| pandas / NumPy 的 API | 那是库不是语言,属于另外的板块 |
| 面向对象设计(继承体系、设计模式) | 写 AI / 数据代码时它不是主要的咬人来源;真正咬人的是「类属性被所有实例共享」这种,讲在 01 章 |
asyncio 完整体系(任务、取消、超时组) |
归 AI全栈 03,04 章只做选择判据 |
📐 七、关于本板块里的数字
⚠️ 这一套里所有「实测」数字都是在同一台机器上真跑出来的,环境写在这里,方便你判断差多少算正常:
| 项 | 值 |
|---|---|
| 系统 / CPU | Windows 11 / 8 逻辑核 |
| Python | CPython 3.13.14(64 位) |
multiprocessing 默认启动方式 |
spawn |
sys._is_gil_enabled() |
True(未开 free-threaded 构建) |
locale.getpreferredencoding(False) |
⚠️ cp936 |
sys.stdout.encoding |
⚠️ gbk |
⭐ 你的绝对数值一定和这里不同 —— 每一处要看的都是相对关系(谁比谁快几倍、峰值内存差几个数量级),不是秒数本身。 最后两行本身就是 10 章 的正题:本仓库有过一次站点从 156 张图掉到 75 张的事故,根因就是那两行。
🔗 这一章连到哪里
| 相关的地方 | 为什么 |
|---|---|
| AI全栈 03 · 后端骨架 | 它讲 async 在 Web 服务里解什么、以及别阻塞事件循环。⭐ 它在第 111 行把 CPU 密集的活指向了「线程池或独立进程」,04 章 补上「什么时候该选哪个」的判据 |
| 机器学习与深度学习基础 附录B-代码速查 | 它的「⚡ 提速」一节给了三招却没给测量手段,05 章 补的就是那半边 |
| 智能体工程教程 18 · 挑战项目A-手搓Agent框架 | 那道题要你「读函数的类型注解和 docstring 自动生成 schema」,它依赖的闭包 / wraps / signature 在 03 章 |
| 强化学习基础 08 · DQN | 那一行 deepcopy(net) 的正确性完全依赖 01 章:写成 = net 会让 target 网络静默失效 |
| 数据这一关 04 · 脏数据的十种形态 | 它讲「这批 CSV 是不是坏的」,10 章 讲「我的进程默认按什么编码读写」,两个视角合起来才完整 |
| 模型上线之后 17 · 版本回溯与可复现 | 它假定「环境能重建」这件事已经成立,08 章 讲怎么重建 |
| 代码题拆解 00 · 怎么刷代码题 | ⭐ 想拿这一套的知识练手:那 25 道题全是可直接运行的 Python,而它们踩的坑正是这里讲的那些 —— 多重赋值的求值顺序(01 章)、dict 保序而 set 不保序(09 章) |
✅ 检查点
- 这一套的立项判据是什么?为什么「这个知识重要」不算证据?
- 三道自测题分别考的是哪三章?它们有什么共同点?
- 第 ① 题为什么三次都返回
[1, 2, 3]? - 第 ③ 题在本机的实测结果是什么?和大多数人的直觉差在哪?
- 三条读法路线分别是什么场景?路线 B 为什么必须把 05 章放第一个?
- 「名字绑到对象」和「缓冲区被共享」为什么要分给两个不同的板块?
- 本板块明确不讲哪五类东西?async 的完整体系归哪里?
- 为什么章里的绝对秒数不用去对?
👀 答案
- 判据是「站内第 X 章第 Y 句依赖了它,而站内没人讲」。因为「重要」是没有边界的标准,按它建板块会无限膨胀、还会和已有内容重叠;而「站内哪句话依赖了它」能被逐条核对。
- ① 可变默认参数 → 01 章;② 生成器只能走一次 → 02 章;③ 多线程对 CPU 活无效 → 04 章。共同点是三个都不报错 —— 报错的 bug 会被修掉,不报错的会一直留着。
- 默认值
[]在定义函数那一刻只创建一次,之后每次调用共用同一个列表,所以f(1) f(2) f(3)三次拿到的都是同一个已经被追加过三次的列表:[1, 2, 3]。 - 串行 0.80 s、4 线程 0.81 s —— 一模一样。直觉是「4 个线程快 3~4 倍」。
- A =「线上崩了要能查」(07→10→01→08)、B =「脚本太慢」(05→04→02→09)、C =「把脚本变成别人能用的东西」(08→06→03→07)。B 必须先读 05,因为不先量就改,改的九成不是瓶颈;05 章还有个实跑例子说明剖析器自己的开销会把两段代码的快慢顺序颠倒过来。
- 因为共享的东西不是一回事:
a = b共享的是同一个对象(名字层面),NumPy 的 view 共享的是同一块内存缓冲区(stride / 偏移层面),机制和急救手段都不同,混在一起讲会让两边都说不清。 - 语法入门、Web 框架用法、pandas / NumPy 的 API、面向对象设计、
asyncio完整体系。async 归 AI全栈 03,本板块 04 章只做「三种并发怎么选」的判据。 - 因为都是在一台特定机器上跑的(Windows 11 / 8 核 / CPython 3.13.14 / spawn / cp936)。每一处要看的是相对关系 —— 谁比谁快几倍、峰值内存差几个数量级 —— 绝对秒数换台机器必然不同。
🛑 可以停在这里
⚡ 走神救援
这一套的定位:站里其余板块讲「用 Python 表达一个想法」,它讲「Python 自己是怎么运作的」——⭐ 因为那些板块里每一次崩、每一次慢、每一次「我这能跑你那不能跑」,都不是模型的问题,是这一层的问题。
⭐⭐ 立项判据不是「这个知识重要」,而是「站内第 X 章第 Y 句依赖了它,而站内没人讲」:
yield全站十几处全在 SSE 流式里用着,没有一处讲它何时暂停;某一章让你亲手造一个工具装饰器,而闭包和签名反射站内一处没讲;DQN 那一行深拷贝写错会让目标网络静默失效——不报错、loss 还在降、只是学不出来;还有一批词全站命中为 0。⭐ 最能说明问题的一条:某个附录有一整节叫「提速」,给了三招却没有一行教怎么测量。三道自测题判定这套适不适合你:可变默认参数会跨调用累积、生成器只能消费一次而第二次求和是 0 且不报错、纯 CPU 活开多线程和串行一样慢。⚠️⭐ 三题的共同点是都不报错——报错的 bug 会被你修掉,不报错的会一直待着。
⭐ 别顺着读,挑一条按问题分的路线:线上崩了要能查 / 脚本太慢 / 把脚本变成别人能用的东西。⚠️ 第二条里测量那一章必须第一个——不先量就改,改的九成不是瓶颈。
四条分工线:「名字绑到对象」归本板块、「缓冲区被共享」归 NumPy、「谁负责释放」归 C++、计时与剖析方法论整块归本板块;async、结构化日志、pytest 都只链过去不重做。
⚠️ 所有数字都在一台机器上实跑,你要看的是相对关系不是秒数;⭐ 而那台机器的默认编码不是 UTF-8 这件事本身就是最后一章的正题——本仓库因此有过一次站点图掉了一半的事故。
下一节 👉 01-名字、对象和绑定.md