☰
单元 00 · 这十章的判断标准
2026/10/17 2:35:04 网站建设 项目流程

阅读时间约 30 分钟 · 本篇任务:说清这个专栏拿什么当「会写 Python」的判据,选定自己的走法,并给你手上那份「这样写更好」的清单标上条件
参考测试代码

导语

你交了一份脚本,评审看了两分钟,问了三个问题。

rows=[rforrinread_all(path)ifr.qty>=3]top=sorted(rows,reverse=True)[:100]seen={r.skuforrinrows}

第一问:「read_all为什么把整个文件读进内存?文件换成 4 GB 呢。」
第二问:「你排完整张表再切前 100,为什么不直接取前 100。」
第三问:「seen打印出来的顺序,换个进程还一样吗。」

三句话你都答得上,答案分别住在三个地方:惰性求值、容器选择、哈希。麻烦出在第二问。你答「heapq.nlargest更快」,评审接着问「快多少,在什么规模上更快」,你就得给数字;而数字一旦给出来,会带着一个条件一起出来。

本机把第 02 章那份 100 万条记录跑了一遍。取前 10 条那一档:sorted229.98–314.76 ms,heapq.nlargest8.84–11.49 ms,差二十六倍。把需求换成「取前 60 万条」,翻转就发生在 k/N 的 4% 到 5% 这一段(4.0% 那一档比值 0.90,5.0% 那一档 1.12),nlargest的便宜没了。「用nlargest」这句话,在 k 小的时候是结论,在 k 大的时候是反例。

这个专栏要做的,就是给这一类结论补上条件,并且把条件做成你能自己复跑的读数。

先说清一件事:这里的「判断标准」有明确所指。它指的是一句话背后的那组数——哪种写法在什么规模、什么数据形状上占便宜,从哪一档开始不占便宜。它不指风格,也不指「Pythonic 不 Pythonic」这种说法。十章的每一章都要交出一组这样的数,交不出来的一章不算写完。

读完这一篇你会拿到三样东西:一张十章地图,标明每章开题的那份数据和它逼出来的那条判据;一份跳读清单,告诉你哪几节赶时间可以跳过、跳过之后缺什么;一份「书上这么写、今天不一定成立」的八行对照——这八处是本专栏实测出来的差异,也是这个专栏存在的最直接理由。


一、机制:三列依据各答一个问题

任何一个「该不该这么写」的问题,拆开都含三个不同的问题,各有各的权威。这个专栏的每一章都按这三列组织:

你在问什么归属本专栏的依据怎么引
Python 为什么这样设计机制Fluent Python2nd Edition(2022)章号 + 小节名
该不该这么写,代价落在谁身上判断Effective Python3rd Edition(2024)条目号
今天(3.14)到底怎么写现状官方文档、PEP、typing 规范节名或 PEP 编号 + 版本归属

回答顺序是机制 → 判断 → 现状。这个顺序在 Python 上有具体的理由:这个语言里绝大多数惯用法都是数据模型推出来的结果,不讲清「解释器在什么时候替你调了哪个方法」,后面的代价就无处可挂。

拿if book:这一句走一遍。机制层告诉你,没有__bool__时解释器退到__len__(官方object.__bool__一节)。判断层因此能问出真问题:你这个__len__是读一个字段,还是扫一遍全部元素。现状层补上版本事实——3.14 起注解延迟求值(PEP 649 / 749),这一条与__bool__无关,但同一个现状列里另一条判据靠它翻面。三列各说一句,谁也不重复谁。

再举一个三列互相顶着的例子,感受一下「冲突时以现状列为准」是什么意思。Fluent Python2e ch15 写「运行期读取类型提示不可靠」,这句话在 2022 年成立;3.14 上 PEP 649 / 749 已经生效,本机实测注解在定义期求值 0 次(3.12.13 上是 2 次 / 3 次),成本搬到第一次读它的那一刻。第 07 章因此照书里原意引一句,紧接着给 3.14 的读数,最后把处理方式落成一条可核对的记录。

再看一处更细的:参数传递到底叫什么。Effective Python3e 条目 30 用的是passed by reference;同一套官方文档里,Tutorial §4.8 的脚注给的是call by object reference,而《Programming FAQ》里写的却是no call-by-reference。三句话指向同一件事,措辞互相顶着。判断列照条目号引用,现状列把官方三句并列摆出来,然后给一条能用的判据:别名只在「对象可变、你在它身上动内容」这一层成立。措辞的出入不是文字游戏——第 06 章要回答的「两次调用拿到的是不是同一个对象」,判据正长在这一层上,措辞含糊会直接把判据带偏。

这两处的处理方式,是全书十章的样板:引一句原意,给一组读数,落一条判据。中间不跳过任何一步,也不因为书上是权威就省掉实测。

一本被淘汰的教材

原本这个位置的第三副「眼镜」是Python Cookbook3rd Edition(中文版豆瓣 9.2,461 人评分)。它被换掉了,理由与内容质量无关:它停在 2013 年的 Python 3.3,比 f-string(3.6)、dataclass(3.7)、海象运算符(3.8)、match(3.10)都早。照它敲出来的写法,很多正是这个专栏要改掉的那一类。它只在个别「老配方 vs 今天的写法」小节里出现,作对照,不作依据。

第三列因此换成官方文档与 PEP 的位置。这件事带来一个副作用,值得提前说:这一列是全书最容易过期的一列,所以每一章写它之前都重新打开官方页面确认一次,版本归属直接写进句子——「3.13 起」「3.14 起」「3.15 才默认开启」各自成句,不含糊成「新版本里」。

一章的固定形状

每章六段固定:导语、机制、判断、现状、一课实验、印证条款,后面再加三级练习、验收自测与术语表附录。

其中一课实验是这个专栏的招牌。同一个知识点写三份实现——朴素版、惯用版、库函数版——拿同一份数据跑出两组读数(耗时给区间并注明采样次数,内存与计数给单值),然后回答一个问题:

惯用写法在什么条件下反而更差。

这个问题不是修辞。十章的实验里有六处给出了正面的答案:

章惯用写法它反而更差的条件本机读数
01自定义容器继承collections.abc,白拿__contains__当__getitem__自己就是 O(i) 时n = 100000:自写 O(1) 版 0.0001–0.0023 ms,白拿的线性版 8.7876–10.3636 ms
02heapq.nlargest取前 k 条k/N 超过 4%–5% 之后k = 600000 / N = 1000000:比值翻到 1.12,sorted反超
03defaultdict处理缺失键缺口比例超过 40%–60% 之后缺口多时setdefault便宜到 0.85×
04格式化一律用 f-string把它当缓冲区、一行一行拼大文本时25 倍输入换来 708 倍耗时,+=只要 23.7 倍
05frozen=True的实例能当字典键字段里有一个list时哈希「生成出来了却用不了」
09生成器流式处理输入管线需要排序时要排序就得走完全部输入;省下的是中间那一份,不是最后那一份

这张表是这个专栏的目录。十条判据的每一条,都以「它的反例长什么样」的形式被写出来。至于「哪些写法在什么条件下值得」这种正向结论,教材里已经写得够多了;本书补的是另一半。


二、判断:十章各自把哪条惯用法逼到墙角

每章开题用一份具体的数据或一段真实的代码,收尾给一条带条件的判据。下表按「开题的那份数据 → 逼出来的判据 → 读完你能做的事」排。

章开题的那份数据逼出来的判据(一句话)读完你能做的事
01 数据模型与协议一个in、一个if obj:collections.abc的 mixin 是给你补方法的,不是给你提速的;__getitem__是 O(i) 时,白拿的那几个方法把代价抬高一到两个数量级说清「一个类要实现哪些方法才算像个容器」,并用实测说明__len__与__contains__的隐式调用代价
02 序列与容器的选择100 万条记录取前 100,再取前 60 万list是默认值,不是答案;heapq的优势随 k/N 单调收窄、必然穿过 1,拐点只能自己扫对一份数据说明「为什么选这个容器」,并给出自己的实测拐点
03 字典与集合的代价同一份集合在四个子进程里打出四种次序dict上每个 O(1) 都是「平均情况」下的 O(1);缺失键的写法没有默认答案,翻转落在缺口比例 40%–60%说清「缺失键」四种处理方式各自的代价,并有内存数字支撑
04 文本与字节一份 982 字节、混了中文与坏字节的输入同一段文本有三套数(字节 / 码位 / 图形字符);errors=决定的是留下多少信息,与快慢无关对三类坏输入都给得出结果或可读报错,且比较不因编码形式不同而误判
05 数据类与结构化数据一行写成dict的订单记录frozen=True一个字节都不省,却让构造贵一倍多;省内存的是slots=True把一行记录从dict换成类,并说清跟着变的==语义、哈希能力、异常类
06 函数与参数设计一个八行长签名的筛选函数默认值表达式的求值次数等于那条def被执行了几次;判「两次调用拿到的是不是同一个对象」只能用is说清什么时候该拆函数、什么时候该换参数对象,并有签名与报错的对照输出
07 类型提示值不值得写〔核心章〕三个核心函数要不要标注,三个人三个答案「标注不改变运行期」只剩一半成立:调用行为没变,注解却不再在定义期求值(3.14 起 0 次)给出「哪些模块标注、哪些不标」的书面判据,以及有数字支撑的注解代价说明
08 装饰器与上下文管理器散落三处的计时、重试、资源清理装饰器做的事情是把函数换掉;换掉之后,读那个对象的人各自拿到不同的东西三处重复逻辑各自只剩一处定义,且异常路径下资源一定被释放
09 生成器与惰性求值〔核心章〕一条「读全量再筛选」的输入管线生成器省的是「同时活着的那一份数据」,代价是只能读一遍与每项一次切帧管线在大文件上的峰值内存低于全量版,且「惰性在什么条件下失效」有一条自己的结论
10 并发选型:线程 / 进程 / 协程〔核心章〕同一批任务交给四条路各跑一遍能力边界由「任务在等还是在算」决定,不由「开了几条线」决定四条路线在同一台机器上都有数字,且能对一份具体任务给出选择理由

四个核心章(01、07、09、10)篇幅按 700 行左右写,其余按 300–450 行写。核心章的判据通常要跨三列才说得清,压缩会压掉条件。

双主线:一条讲判断,一条改代码

这个专栏有两条线同时走,每章各推进一格。

A 线是对拍实验,也就是上面那张表里的读数来源。它回答「懂不懂」。

B 线是一个贯穿全书的项目,一个叫datanote的小工具:扫一份记录、按条件筛、出一份报告。它在第 01–08 章从 v0.5 长到 v0.6——记录类型从字典换成数据类、长签名收成参数对象、核心模块补类型提示、重复的计时与重试收敛到装饰器与上下文管理器;第 09–10 章长到 v0.7——输入管线改成流式,多文件读取改并发,测试覆盖全部模块并在 CI 上跑同一套验证。它回答「会不会用」。

B 线只给「改前 / 改后」两列,不给速度承诺。这是刻意的:判断力的一部分就是知道哪一处改动的收益可以承诺、哪一处只能给出区间。

两条线在每章各占一块,写法的差别也很明显。A 线要的是数字,所以它关心探针怎么搭、区间怎么采、哪些量可以计数;B 线要的是「改完之后读者读到的代码有没有变短」,所以它只贴两段代码的前后对照。有一条纪律两条线共用:章与章之间不许套同一个分段结构。十章的导语写法、实验记录的呈现方式(有的用表格、有的给折线数据、有的逐条贴输出)、章末收尾格式,各自都不一样。这样安排有具体理由——同一本书里十个模子印出来的章节,读到第五章读者就开始跳着看了。


三、现状:基线,与八处「书上这么写、今天不一定成立」

基线

项值
解释器CPython 3.14.4
声明范围>=3.13,<3.15,按 3.13 及以上写,实测在 3.14,不假设 3.15 的行为
对照解释器3.12.13(用于两版对照的那几组读数)
平台Ubuntu,Linux x86_64
UTF-8 模式sys.flags.utf8_mode == 0(3.15 才默认开启,PEP 686)
运行环境本机虚拟环境,pytest + pytest-timeout

耗时类数字统一给区间加采样次数(timeit.repeat(repeat=15),报最小值–最大值),并标明是本机参考值;绝对耗时不可跨机器跨负载比较,这句话在每一章的实验里都会出现一次。尺寸、计数、调用次数这类确定性数字给单值,它们不受负载影响,可以跨机器引用——能计数就别计时,这是本专栏的计量偏好。

与之配套的是反例隔离:每一章都有一份故意写坏、命名带_broken的实现,配一组标了broken的测试。它的用途是把上面那些「八处对照」变成可复跑的现场,而不是一段回忆。规矩有两条:反例必须真跑一次,标成「预期红」的用例若总是通过,它就构不成反例,这时如实写出来、不假称它红了;正文里贴的每一段 traceback 都要能在这套基线上复现,并标出是哪个版本——报错文案会随版本变,这八处对照里有两处正是文案变了。

出处这一层也有一条规定:核不到就标「未核实」,不许写章号页码。教材引文先查全文再写,中文引文标「他在第 N 章第 M 节写」或注明是译文;拿不准的地方宁可留一个「未核实」,也不要补一个看起来像样的页码。

八处对照

下面八处是这个专栏在实测中发现与教材不符的地方。它们不是「书上写错了」,多数是书写完之后版本动了;列在这里,是因为它们最能说明「为什么第三列要单独立一列」。

#书上这么写今天为什么不成立落在哪一章
1Effective Python3e 条目 11:格式化一律用 f-string把它当缓冲区、一行一行拼大文本时,25 倍输入换来 708 倍耗时,而+=只要 23.7 倍04
2条目 56:frozen=True的实例能当字典键、能进set本机四个组合里有两份做不到:默认参数的数据类__hash__是None;frozen=True配一个list字段则「生成出来了却用不了」05
3条目 30:参数是passed by reference同一套官方文档的 FAQ 写的是no call-by-reference,Tutorial §4.8 的脚注给的措辞是call by object reference06
4条目 36:默认值during function definition at module load time求值一次实测求值次数等于那条def被执行了几次:外层调两次就是两次,循环里五次就是五次06
5条目 124:前向引用要加引号,否则定义期抛NameError3.14 起注解延迟求值,那个例子在定义期不再抛;加引号的写法仍然可用,只是理由过期了07
6Fluent Python2e ch15:运行期读取类型提示不可靠PEP 649 / 749 从 3.14 生效;本机实测定义期求值 0 次(3.12.13 上是 2 / 3 次)07
7条目 38:pickle失败抛AttributeError3.14 上换成PicklingError(gh-122311),在pickle.dumps外面写except AttributeError的代码接不住08
8条目 21 给的防御式写法(对传进来的可迭代参数先list())传进来的是一次性迭代器时,取走的项数一项都没多,调用方那边却静默变成[]09

另外三处不算「不符」,算「书上没写、本机可复现」,也一并记着:slots=True与frozen=True同开时,赋给字段名抛FrozenInstanceError、赋给任何别的名字抛TypeError(根因是slots=True返回新类,官方文档未写,CPython 已登记);@dataclass的逐字段比较在 3.13 改了行为,同一个 NaN 字段的相等判断在两版上是两个答案;functools.wraps在 3.14 把元数据清单第 5 项从__annotations__换成了__annotate__,官方那一页没有记这次替换。

与下一次的分界:这里不讲什么

这个专栏讲「协议怎么写、什么时候写」,不讲「属性查找顺序为什么是这样」;讲「类型提示值不值得写」,不讲「注解在解释器里怎么存储」;讲「并发选型的判据」,不讲「GIL 的实现与 free-threaded 构建的内部结构」。

具体划掉的内容有四类:元类与类元编程(第 01、08 章各提一句边界,完整机制留给讲「类是怎么造出来的」那一期);字节码、dis、GC 调参;描述符查找的完整优先级链;框架源码通读与打包分发。这四类都在下一次的《Python 内里》里,讲了这里也不重复。

还有一类不进正文:工具的口味。列宽、命名、导入顺序这些交给格式化与静态检查工具,讲义只讲它们背后的取舍(比如「PEP 8 的 79 列是标准库的自我约束,Black 与 Ruff 默认 88 列」),不在这里定规矩。


四、怎么读:四条路径与一份跳读清单

四条路径

走法路径适合谁读多少
顺序读(默认)01 → 10,每周 2.5 章从头跟到尾,每周约 6 小时全部
判断优先01 → 03 → 05 → 07 → 10,只读判断列与验收标准,不跑 A 线实验手上有自己的项目、只想改写法约一半
重构优先01 → 05 → 07 → 08 → 09,跟着 B 线走只想把代码改得能被别人读全部,但跳过部分机理推导
回来查只读每章的三列依据表与「验收标准」遇到具体问题时当手册用按需

顺序读是默认,理由与三列的依赖顺序有关:第 01 章的数据模型是后面九章的落点,第 03 章的顺序保证、第 04 章的规范化、第 09 章的一次性迭代器,都会在第 10 章的并发读数里再出现一次。

跳读清单

这十章的阅读量不轻:Fluent Python精读约 550 页,Effective Python3e 按章取约 85 条、差不多 250 页,合计约 800 页压在 4 周里。下面这几处可以跳,跳过不影响判据的成立:

  • Fluent Pythonch15 的泛型变体那一节。第 07 章讲类型提示成本时用不到变体规则;用到时那一节回头再翻。
  • Fluent Pythonch13 的 goose typing 一节的后半。第 01 章只取它一句结论(四条类型路线互补),推导过程不影响判据。
  • Effective Python第 11、12 章的部分条目。这两章讲的是性能剖析与内存,与第 02、03 章的主题相邻但不重合,本专栏只在两处引用它们的结论。
  • 每章实验里的「计数指标」那一组,赶时间可以先只读结论行。判断只依赖「哪个更快」,归因才需要计数;而判据的成立不靠归因。

不能跳的是每章的「招牌结论」与「验收标准」:前者是那一章的判据,后者是你能不能自己判对错的依据。

一处要提前交代的读法问题

Fluent Python第 2 版中文版豆瓣 8.2(132 人评分),1 星占 18.9%,差评集中在翻译;英文原版在 Goodreads 是 4.6(1,845 人)。这个差距是真的,但它不该变成「我读不懂」的自我怀疑。三条对策,挑一条就行:

  1. 对照官方示例仓库读原文(fluentpython/example-code-2e,作者维护,与书中代码一一对应)。读代码比重读译文快得多。
  2. 只精读约 15 章,其余按需查。本专栏依赖的机制章是 ch1–ch9、ch11、ch13、ch17–ch21,其余章只作背景。
  3. 直接读英文第 2 版,中文版当术语对照表用。

还有一层要分开的情境:翻译问题与代际问题是两件事。书里说「注解在导入时求值」,中文版翻得没错,那是截至 Python 3.10 的标准行为;3.14 上这一条已经不成立。遇到这一类段落,讲义的固定处理方式是「照书中原意引一句 + 立刻给 3.14 的现状与本机实测」,并把差异落成可核对的记录——上面那八处,都是按这个流程走出来的。


印证条款

结论依据来源与位置
特殊方法由解释器调用,不由你调用;惯用法的根在数据模型Fluent Python2e ch1「How Special Methods Are Used」(英文 PDF 正文页 7)
无__bool__时真值判断退到__len__官方《Data model》参考章节object.__bool__一节;本机探针实测
heapq与sorted的取舍随 k/N 移动官方heapq文档的性能说明;本机扫描 N = 1000000,翻转落在 k/N 的 4%–5%
dict的 O(1) 是平均情况下的结论官方《Time complexity of operations on built-in types》;本机碰撞计数实验(一格 800 个键、319,600 次__eq__)
dict插入序是语言保证,set迭代序不在任何保证内官方dict文档视图对象一节与set类型一节;本机四子进程对照实测
UTF-8 模式 3.15 才默认开启,今天不写encoding仍有风险PEP 686(Python will enable UTF-8 mode by default from Python 3.15);本机 3.14.4 实测sys.flags.utf8_mode == 0
@dataclass的frozen/slots各有代价,官方文档未记两者的冲突官方dataclasses文档field/Frozen instances各节;本机四种组合实测(其中slots+frozen的异常类型已由 CPython 登记)
参数按对象引用传递;官方三句措辞互不相同官方《Function definitions》§8.7、《More on Defining Functions》Tutorial §4.8 脚注、官方《Programming FAQ》
注解从 3.14 起延迟求值;PEP 563 已作废PEP 649 / PEP 749(Final,Python-Version 3.14);PEP 563(Status: Superseded,Superseded-By: 649, 749);官方__future__页把 Mandatory in 写成Never
官方文档明确列出了「不该上静态类型检查」的情形官方《Reasons to avoid static type checking》,其中引 PEP 484 的原句说明类型提示本来就不打算变成强制
functools.wraps在 3.14 换了元数据清单第 5 项本机 3.14.4 与 3.12.13 对照实测;官方functools文档那一页只记了 3.12 增加__type_params__
with块在五条退出路径上__exit__都恰好调用一次官方语言参考《The with statement》;本机五条路径对照实测
生成器只省「同时活着的那一份数据」官方语言参考《Yield expressions》《Iterator Types》;本机tracemalloc峰值对照(562,432 字节对 752 字节,探针形态写进读数)
并发能力边界取决于任务在等还是在算官方concurrent.futures/threading/asyncio文档;PEP 703 / 779(free-threaded 从实验升为正式支持,仍不是默认构建)、PEP 734(多解释器进标准库);本机四条路对照读数
Python Cookbook3e 不进依据列该版基线停在 2013 年的 Python 3.3,早于 f-string、dataclass、海象运算符与match

三条取材说明。①两本教材的引文都逐字核过全文:Fluent Python2e 英文 PDF 转文本(页码保留在文本里,故可给正文页)、Effective Python3e EPUB 转文本(没有页码,引用一律给「章号 + 条目号」)。②Fluent Python的立场只能从书里正文读出来,所以一律写成「他在第 N 章第 M 节写」;Effective Python3e 的作者立场多来自书外访谈与博客,句式写成「他在 X 年 Y 场合说」。两者的材料形态不对称,句式不混用。③本章表格里的每一个数字都能在对应章节的正文里找到完整读数与命令;单源结论会降级标注,镜像不算第二源。


练习

三级梯度,做完一级再看下一级。

E00.1〔照着做〕给你最常用的五条写法各补一个条件。

打开你手上正在维护的那个项目,挑五条你「一直这么写、从没想过为什么」的写法(例如「字典查缺失键用get」「循环里拼字符串用 f-string」「函数参数超过四个就传字典」)。每条写成两列:写法、它的前提。前提写不出来的那几条,标成待查。

验收:五条都有前提,其中至少两条你能说出现在这个前提在你的代码里成不成立。写不出前提的那几条不算做完,它们是第 03、04、06 章要正面回答的对象。

E00.2〔改一改〕给一条惯用写法设计一个翻转实验。

从 E00.1 里挑一条,设计一组能让它「从更优变成更差」的实验。要求三件事:同一份数据、两份实现、至少四档规模。跑完给出一个拐点,并写清这个拐点在你机器上、在你这份数据上的位置。

验收:给出四档以上的读数(耗时给区间加采样次数,计数给单值),外加一句「拐点在 X 附近,换成别的数据形状它会移动」的说明。只给一档数字不算做完——一档数字撑不起「更好」这个词。

E00.3〔深〕把「现状」这一列自己走一遍。

选一条你在用的写法,去找它今天的官方说明:先在官方文档或 PEP 里定位到那一节,确认它是哪个版本引入的、哪个版本改过行为,然后把原句抄下来。抄完之后做一件事——去找比它更新的版本有没有改动这条(例如你是从 3.13 的页面读到的,去 3.14 的 What’s New 里搜一遍)。

验收:一段不超过 150 字的说明,包含三样东西:官方原文一句、版本归属(哪个版本起)、以及你判断它「今天还成立」的理由。找不到官方出处的一条,如实写「未核到」,不要用博客或问答站代替官方文档。


验收自测

先自己答,再展开对答案。

  1. 这个专栏的每一章为什么要分机制、判断、现状三列?三列冲突时以哪一列为准,为什么?
  2. 「惯用写法在什么条件下反而更差」——这个专栏为什么把这一问当成每章的必答题,而不是先给「最佳实践」?
  3. 你手上有一条用了三年的写法。要判断它今天还成不成立,你最少要查几样东西?
答案
  1. 因为一个「该不该这么写」的问题里其实含三个不同的问题,各有各的权威:为什么这样设计(Fluent Python2e,标章号与小节名)、该不该这么写(Effective Python3e,标条目号)、今天到底怎么写(官方文档与 PEP,标版本归属)。两本教材分别写于 2022 年(覆盖 3.10)与 2024 年(覆盖 3.13),它们的时效锚点都落后于基线,凡是涉及版本行为的句子都可能过期,所以冲突时以现状列为准,并把差异逐条列出来。本章「八处对照」就是这条规则的产物。

  2. 因为正向结论在教材里已经写满了,缺的是另一半。一本讲「应该这么做」的书,读者读完会得到一批没有条件的规则;而规则一旦脱离条件,就退化成了偏好。补条件的唯一办法是把反例跑出来——所以每章都要写三份实现、留一份「让惯用写法输掉」的读数。第 02 章的 k/N 拐点、第 04 章的 f-string 放大 708 倍、第 05 章的frozen=True哈希失败,都是这么来的。

  3. 最少三样。①写法本身在官方文档或 PEP 里的原句,确认它的准确措辞(很多出入出在措辞上,例如参数传递到底叫什么)。②它的版本归属:哪个版本引入、哪个版本改过行为,这决定了你的写法在>=3.13,<3.15的哪一端成立。③比它更新的版本有没有动它,也就是目标版本的 What’s New 里搜一遍相关词。三样齐了才谈得上「今天还成立」;缺哪一样,就在结论里如实标出来。


附录 · 术语表

术语一句话解释首次出现
判断力(judgment)知道一条写法在什么规模、什么数据形状上占便宜,从哪一档开始不占便宜§导语
三列依据本专栏每章的取材结构:机制(为什么这样设计)、判断(该不该这么写)、现状(今天到底怎么写)§一
机制列三列的第一列,依据取Fluent Python2nd Edition,标章号与小节名§一
判断列三列的第二列,依据取Effective Python3rd Edition,标条目号,正文不复述条目内容§一
现状列三列的第三列,依据取官方文档与 PEP,逐句标版本归属;与两本教材冲突时以它为准§一
版本归属一条行为事实挂在哪几个版本上的写法:「3.13 起」「3.14 起」「3.15 才默认开启」,不含糊成「新版本里」§一
一课实验每章的固定产出:同一份数据写朴素版、惯用版、库函数版三份实现,测出惯用版在什么条件下反而更差§一
招牌结论一章的判据,写成「条件下的一句话」,通常放在实验结尾的引用块里§一
基线全文实测所依据的环境:CPython 3.14.4、声明范围>=3.13,<3.15、对照解释器 3.12.13§三
印证条款每章末尾的三列表:结论、依据来源与位置;英文引文逐字,核不到的标「未核实」§印证条款
三级梯度每章练习的三档:照着做、改一改、自己设计;第三级标〔深〕§练习
双主线A 线对拍实验(回答「懂不懂」)与 B 线贯穿项目重构(回答「会不会用」)并行推进§二

本表只收本章首次引入的词,共 12 条。对拍实验的定义在第 01 章的术语表里,本章只使用、不重收。后续章节重复出现的词不再重复收录。


→ 第 01 章从这里开始:一个in与一个if obj:,引出特殊方法由谁调用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询