阅读时间约 30 分钟 · 本篇任务说清这个专栏拿什么当「会写 Python」的判据选定自己的走法并给你手上那份「这样写更好」的清单标上条件参考测试代码导语你交了一份脚本评审看了两分钟问了三个问题。rows[rforrinread_all(path)ifr.qty3]topsorted(rows,reverseTrue)[:100]seen{r.skuforrinrows}第一问「read_all为什么把整个文件读进内存文件换成 4 GB 呢。」第二问「你排完整张表再切前 100为什么不直接取前 100。」第三问「seen打印出来的顺序换个进程还一样吗。」三句话你都答得上答案分别住在三个地方惰性求值、容器选择、哈希。麻烦出在第二问。你答「heapq.nlargest更快」评审接着问「快多少在什么规模上更快」你就得给数字而数字一旦给出来会带着一个条件一起出来。本机把第 02 章那份 100 万条记录跑了一遍。取前 10 条那一档sorted229.98–314.76 msheapq.nlargest8.84–11.49 ms差二十六倍。把需求换成「取前 60 万条」翻转就发生在 k/N 的 4% 到 5% 这一段4.0% 那一档比值 0.905.0% 那一档 1.12nlargest的便宜没了。「用nlargest」这句话在 k 小的时候是结论在 k 大的时候是反例。这个专栏要做的就是给这一类结论补上条件并且把条件做成你能自己复跑的读数。先说清一件事这里的「判断标准」有明确所指。它指的是一句话背后的那组数——哪种写法在什么规模、什么数据形状上占便宜从哪一档开始不占便宜。它不指风格也不指「Pythonic 不 Pythonic」这种说法。十章的每一章都要交出一组这样的数交不出来的一章不算写完。读完这一篇你会拿到三样东西一张十章地图标明每章开题的那份数据和它逼出来的那条判据一份跳读清单告诉你哪几节赶时间可以跳过、跳过之后缺什么一份「书上这么写、今天不一定成立」的八行对照——这八处是本专栏实测出来的差异也是这个专栏存在的最直接理由。一、机制三列依据各答一个问题任何一个「该不该这么写」的问题拆开都含三个不同的问题各有各的权威。这个专栏的每一章都按这三列组织你在问什么归属本专栏的依据怎么引Python 为什么这样设计机制Fluent Python2nd Edition2022章号 小节名该不该这么写代价落在谁身上判断Effective Python3rd Edition2024条目号今天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.2461 人评分。它被换掉了理由与内容质量无关它停在 2013 年的 Python 3.3比 f-string3.6、dataclass3.7、海象运算符3.8、match3.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 ms02heapq.nlargest取前 k 条k/N 超过 4%–5% 之后k 600000 / N 1000000比值翻到 1.12sorted反超03defaultdict处理缺失键缺口比例超过 40%–60% 之后缺口多时setdefault便宜到 0.85×04格式化一律用 f-string把它当缓冲区、一行一行拼大文本时25 倍输入换来 708 倍耗时只要 23.7 倍05frozenTrue的实例能当字典键字段里有一个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的订单记录frozenTrue一个字节都不省却让构造贵一倍多省内存的是slotsTrue把一行记录从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用于两版对照的那几组读数平台UbuntuLinux x86_64UTF-8 模式sys.flags.utf8_mode 03.15 才默认开启PEP 686运行环境本机虚拟环境pytest pytest-timeout耗时类数字统一给区间加采样次数timeit.repeat(repeat15)报最小值–最大值并标明是本机参考值绝对耗时不可跨机器跨负载比较这句话在每一章的实验里都会出现一次。尺寸、计数、调用次数这类确定性数字给单值它们不受负载影响可以跨机器引用——能计数就别计时这是本专栏的计量偏好。与之配套的是反例隔离每一章都有一份故意写坏、命名带_broken的实现配一组标了broken的测试。它的用途是把上面那些「八处对照」变成可复跑的现场而不是一段回忆。规矩有两条反例必须真跑一次标成「预期红」的用例若总是通过它就构不成反例这时如实写出来、不假称它红了正文里贴的每一段 traceback 都要能在这套基线上复现并标出是哪个版本——报错文案会随版本变这八处对照里有两处正是文案变了。出处这一层也有一条规定核不到就标「未核实」不许写章号页码。教材引文先查全文再写中文引文标「他在第 N 章第 M 节写」或注明是译文拿不准的地方宁可留一个「未核实」也不要补一个看起来像样的页码。八处对照下面八处是这个专栏在实测中发现与教材不符的地方。它们不是「书上写错了」多数是书写完之后版本动了列在这里是因为它们最能说明「为什么第三列要单独立一列」。#书上这么写今天为什么不成立落在哪一章1Effective Python3e 条目 11格式化一律用 f-string把它当缓冲区、一行一行拼大文本时25 倍输入换来 708 倍耗时而只要 23.7 倍042条目 56frozenTrue的实例能当字典键、能进set本机四个组合里有两份做不到默认参数的数据类__hash__是NonefrozenTrue配一个list字段则「生成出来了却用不了」053条目 30参数是passed by reference同一套官方文档的 FAQ 写的是no call-by-referenceTutorial §4.8 的脚注给的措辞是call by object reference064条目 36默认值during function definition at module load time求值一次实测求值次数等于那条def被执行了几次外层调两次就是两次循环里五次就是五次065条目 124前向引用要加引号否则定义期抛NameError3.14 起注解延迟求值那个例子在定义期不再抛加引号的写法仍然可用只是理由过期了076Fluent Python2e ch15运行期读取类型提示不可靠PEP 649 / 749 从 3.14 生效本机实测定义期求值 0 次3.12.13 上是 2 / 3 次077条目 38pickle失败抛AttributeError3.14 上换成PicklingErrorgh-122311在pickle.dumps外面写except AttributeError的代码接不住088条目 21 给的防御式写法对传进来的可迭代参数先list()传进来的是一次性迭代器时取走的项数一项都没多调用方那边却静默变成[]09另外三处不算「不符」算「书上没写、本机可复现」也一并记着slotsTrue与frozenTrue同开时赋给字段名抛FrozenInstanceError、赋给任何别的名字抛TypeError根因是slotsTrue返回新类官方文档未写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.2132 人评分1 星占 18.9%差评集中在翻译英文原版在 Goodreads 是 4.61,845 人。这个差距是真的但它不该变成「我读不懂」的自我怀疑。三条对策挑一条就行对照官方示例仓库读原文fluentpython/example-code-2e作者维护与书中代码一一对应。读代码比重读译文快得多。只精读约 15 章其余按需查。本专栏依赖的机制章是 ch1–ch9、ch11、ch13、ch17–ch21其余章只作背景。直接读英文第 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 686Python will enable UTF-8 mode by default from Python 3.15本机 3.14.4 实测sys.flags.utf8_mode 0dataclass的frozen/slots各有代价官方文档未记两者的冲突官方dataclasses文档field/Frozen instances各节本机四种组合实测其中slotsfrozen的异常类型已由 CPython 登记参数按对象引用传递官方三句措辞互不相同官方《Function definitions》§8.7、《More on Defining Functions》Tutorial §4.8 脚注、官方《Programming FAQ》注解从 3.14 起延迟求值PEP 563 已作废PEP 649 / PEP 749FinalPython-Version 3.14PEP 563Status: SupersededSuperseded-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 / 779free-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 字的说明包含三样东西官方原文一句、版本归属哪个版本起、以及你判断它「今天还成立」的理由。找不到官方出处的一条如实写「未核到」不要用博客或问答站代替官方文档。验收自测先自己答再展开对答案。这个专栏的每一章为什么要分机制、判断、现状三列三列冲突时以哪一列为准为什么「惯用写法在什么条件下反而更差」——这个专栏为什么把这一问当成每章的必答题而不是先给「最佳实践」你手上有一条用了三年的写法。要判断它今天还成不成立你最少要查几样东西答案因为一个「该不该这么写」的问题里其实含三个不同的问题各有各的权威为什么这样设计Fluent Python2e标章号与小节名、该不该这么写Effective Python3e标条目号、今天到底怎么写官方文档与 PEP标版本归属。两本教材分别写于 2022 年覆盖 3.10与 2024 年覆盖 3.13它们的时效锚点都落后于基线凡是涉及版本行为的句子都可能过期所以冲突时以现状列为准并把差异逐条列出来。本章「八处对照」就是这条规则的产物。因为正向结论在教材里已经写满了缺的是另一半。一本讲「应该这么做」的书读者读完会得到一批没有条件的规则而规则一旦脱离条件就退化成了偏好。补条件的唯一办法是把反例跑出来——所以每章都要写三份实现、留一份「让惯用写法输掉」的读数。第 02 章的 k/N 拐点、第 04 章的 f-string 放大 708 倍、第 05 章的frozenTrue哈希失败都是这么来的。最少三样。①写法本身在官方文档或 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:引出特殊方法由谁调用。