Chapter 62: CPython Source Tree
阅读 CPython 源码的第一步,是把一个 Python 现象放回源码树中的位置。源码树的目录名本身就是一组分层线索:对象实现、解释器执行、公开 C API、语法解析、C 扩展模块、Python 标准库、启动路径和运行时引导分别落在不同目录中。读完本章后,读者应能根据一个短 Python 程序,判断应该先进入哪个目录,再沿着哪些边界继续追踪。
本章以 CPython 为边界。CPython 是 Python 语言的参考实现之一,本章讨论的文件名、目录结构和初始化路径属于 CPython 实现细节。阅读本机源码时,应优先选择与本机解释器版本一致的 tag;阅读公开仓库时,可以从 python/cpython 的顶层目录开始。不同版本会移动局部文件或拆分内部结构,本章建立的是目录级定位模型。
贯穿本章的材料是下面这个短程序。它同时触发启动、解析、编译、模块导入、类创建、对象属性、dict、unicode 和标准库调用,足够覆盖本章要定位的主要目录。
import json
class Box:
def __init__(self, value):
self.value = value
payload = {"value": Box(3).value}
print(json.dumps(payload))
这个程序进入 CPython 后,先经过启动路径和 runtime bootstrap,再把源码文本交给 parser 和 compiler,随后在 frame 中执行字节码。执行期间,Box、function、dict、unicode、module、builtins、exception indicator 和 C API 声明会分别落到不同源码区域。源码阅读的稳定顺序是:先判断当前现象属于语法、对象、执行、模块、C API 还是启动,再进入对应目录;进入文件后再追踪函数、结构体、slot 和错误路径。
下面这张图只表达目录定位,不表达具体函数调用栈。后续章节会进入 typeobject.c、dictobject.c、ceval.c 等具体文件;本章先建立源码树的地图。
图中的主线是 python app.py 从进程入口走到解释执行。Parser/ 负责把文本转成语法结构,Python/ 承接编译、执行和运行时管理,Objects/ 提供对象行为,Lib/ 和 Modules/ 提供标准库两种实现形态,Include/ 则把 C 结构、宏和 API 边界暴露给解释器内部和扩展模块。
62.1 Objects/
Objects/ 是 CPython 对象层的主要实现目录。这里的“对象层”指 Python 层能观察到的 object、type、dict、list、str、function、descriptor 等对象,在 C 层如何分配、初始化、查找、调用、比较、释放。遇到“某个 Python 对象为什么这样表现”的问题,通常先在 Objects/ 建立对象级解释,再回到执行路径看谁触发了这个行为。
贯穿示例中的 Box 会产生一个 type object。class Box: 语句执行时,编译器已经把 class body 编译成 code object;运行时再创建 class namespace,执行 class body,最后调用 metaclass 创建类型对象。这个类型对象的创建、slot 初始化、MRO、attribute lookup 和 descriptor 规则,都属于 Objects/typeobject.c 的阅读范围。下一章会深入 typeobject.c;本章只要求先把“类创建和属性查找”定位到 Objects/。
__init__ 在 Python 层是函数,在 CPython 中对应 function object。function object 保存 code object、globals、defaults、closure、annotations 和调用入口。读取 Box(3) 时,调用路径会把 type 的 call 行为、实例分配、初始化函数调用串起来。这个现象跨越 Objects/typeobject.c、Objects/funcobject.c、Objects/methodobject.c 和 Python/ceval.c,目录定位时先把对象本身放入 Objects/,再把字节码执行放入 Python/。
payload = {"value": Box(3).value} 会创建 dict 和 unicode。dict 的 hash、key equality、插入顺序、resize 和 lookup 都能在 Objects/dictobject.c 找到核心实现;字符串对象的内部表示、interning、hash cache 和编码边界则进入 Objects/unicodeobject.c。当读者观察到 dict 查找快、字符串能作为 key、属性名也是字符串时,Objects/ 给出对象表示和操作成本的解释。
descriptor 也在 Objects/ 中占据核心位置。Python 中函数、property、getset descriptor、member descriptor 都会影响 attribute access。读取 Box(3).value 这种普通实例属性时,实例 dict 是主要路径;读取 Box.__init__ 或 instance.__init__ 时,函数对象作为 non-data descriptor 参与绑定。源码树定位时,凡是“点号访问之后返回值为什么变成另一个对象”的问题,都应把 Objects/typeobject.c 与 Objects/descrobject.c 放入第一圈。
GC 参与对象也能从 Objects/ 看到入口。容器对象持有其它对象引用,部分对象需要 cyclic GC tracking。list、dict、function、tuple 等对象在构造和释放路径中会和 GC、引用计数、allocator 发生连接。定位内存问题时,Objects/ 给出对象是否持有引用、何时增加或减少引用、对象是否进入 GC tracking;更底层的 arena、pool、block 管理会在后续 obmalloc.c 章节展开。
阅读 Objects/ 时,稳定检查顺序是:先确定对象类型,再找对应 *object.c 文件;接着看该类型的 PyTypeObject 或相关 slot;然后看创建、访问、修改、释放路径;最后把错误返回和引用所有权放回 C API 约定。这个顺序能把 Python 层现象拆成对象身份、类型行为、slot 分发和生命周期四个判断点。
62.2 Python/
Python/ 是解释器核心逻辑目录。它处理源码编译、符号分析、字节码生成、frame 执行、异常状态、runtime 初始化、path config、import 底层支撑和解释器生命周期。遇到“程序如何执行到这里”“名字如何解析成局部变量或全局变量”“异常如何传播”“解释器如何启动”的问题,通常要进入 Python/。
贯穿示例中的 class body、函数定义、dict literal、attribute load 和 function call 都会先被编译成字节码。源码文本进入语法分析后,编译阶段会建立 symbol table,判断名字属于 local、global、free、cell 或 builtins lookup 的某一类,再生成不同 opcode。这个阶段常见入口在 Python/symtable.c、Python/compile.c 和相关 compiler 文件中。
执行阶段会进入 evaluation loop。print(json.dumps(payload)) 这种表达式在 frame 中运行:value stack 保存中间值,opcode 触发名字查找、属性读取、调用和返回。执行 loop 本身属于 Python/ceval.c 及其拆分文件范围;具体对象行为会再分发到 Objects/。因此源码阅读要把“执行调度”和“对象行为”分层:opcode 负责选择动作,对象 slot 负责给出类型相关结果。
import json 的底层连接也会经过 Python/。高层 import algorithm 主要在 Lib/importlib/ 中以 Python 代码组织,但解释器需要提供 frozen importlib、module object、import lock、sys modules cache 和 C 层入口。阅读 import 问题时,Python/import.c、runtime 初始化文件和 Lib/importlib/ 通常要同时出现:前者建立解释器能力,后者表达 Python 层查找和加载协议。
错误处理也是 Python/ 的核心职责之一。CPython C API 通常使用返回值配合 thread state 中的 exception indicator 表达失败。字节码执行、函数调用、模块导入和对象操作产生错误后,需要把 C 层失败转换成 Python 层异常,再连接 traceback、frame 和调用栈。定位“为什么这里抛出这个异常”时,读者要同时看 Python/ 的异常传播路径和 Objects/ 的对象级错误设置。
源码阅读时可以把 Python/ 当成控制平面。它决定程序从文本变成可执行 code object 的过程,决定 frame 如何推进,决定 runtime state 何时初始化和清理;但它通常不会在同一位置实现每个对象的全部细节。稳定判断是:当问题问“什么时候执行、怎样调度、如何传播状态”时进入 Python/;当问题问“某个对象为什么给出这个结果”时回到 Objects/。
下面的命令只作为本地源码定位辅助。它们回答“某个符号或文件在哪个目录”,不直接给出语义结论。
CPYTHON_SRC=/path/to/cpython
find "$CPYTHON_SRC/Python" -maxdepth 1 -type f | sort | head
grep -R "PyRun" "$CPYTHON_SRC/Python" "$CPYTHON_SRC/Modules" | head
执行命令后,读者仍要回到源码结构判断:PyRun 一类入口说明 Python 代码如何被提交给解释器,ceval 一类文件说明 frame 如何推进,compiler 文件说明 AST 如何变成 code object。命令提供入口,目录模型提供阅读顺序。
62.3 Include/
Include/ 是 C API 和内部声明的边界目录。它把对象布局、宏、函数声明、slot 编号、runtime state 结构和 public/internal header 分层暴露给 CPython 自身、标准库 C 扩展和第三方扩展。阅读 Include/ 的核心问题是:某个 C 层名字属于公共 API、CPython-specific API 还是内部实现接口。
Include/object.h、Include/abstract.h、Include/typeobject.h 等头文件承载常见对象和抽象协议声明。扩展模块通过这些声明调用 CPython 提供的能力,例如创建对象、增加引用、解析参数、设置异常、访问 buffer protocol。贯穿示例不直接写 C 扩展,但 json.dumps 若进入 C accelerator,相关 C 文件就需要通过 Include/ 中声明的 API 与解释器对象交互。
Include/cpython/ 表达 CPython-specific header 边界。这里的声明常常比 stable ABI 更靠近 CPython 实现细节,能帮助 CPython 自身或版本绑定扩展读取更具体的结构。使用这类 header 会增加版本耦合,源码阅读时可以用它理解对象布局,但扩展设计时要把兼容性成本单独列出。
Include/internal/ 表达内部实现边界。文件名常带有 pycore_ 前缀,服务 CPython 内部编译单元之间共享 runtime state、interpreter state、thread state、GC、allocator 或配置结构。读者在 Python/ 或 Objects/ 中看到 _Py 前缀函数、_PyRuntimeState、PyInterpreterState 或 PyThreadState 时,常常需要进入 Include/internal/ 找结构声明和字段语义。
slot 相关声明也在 Include/ 中形成重要地图。number、sequence、mapping、buffer、call、getattro 等 slot 把 Python 操作连接到 C 函数指针。len(Box()) 会走 special method 相关查找和 slot 调度;虽然本章示例没有调用 len,但 Box(3) 的 type call 行为已经体现了“Python 操作 → type slot → C 函数”的阅读模式。
阅读 Include/ 时要先判断边界级别。public API 能作为扩展模块的稳定入口;CPython-specific header 能解释实现细节;internal header 服务 CPython 自身。这个边界判断会影响结论的适用范围:公共声明可以支撑扩展开发判断,internal 声明主要支撑 CPython 源码阅读和版本内实现解释。
一个可复用检查顺序是:先看 include 路径属于 Include/、Include/cpython/ 还是 Include/internal/;再看符号前缀是 Py、_Py 还是文件内 static;接着看声明是否配套出现在 Doc/c-api/ 或官方 C API 文档;最后把它和当前 CPython 版本绑定。这样能把“能否依赖这个符号”从“能否读懂这个符号”中分离出来。
62.4 Parser/
Parser/ 负责源码文本进入语法世界的前半段。它处理 tokenizer、PEG parser、语法错误定位、AST 入口和 parser generator 相关代码。现代 CPython 的 grammar 资料还会涉及顶层 Grammar/ 目录;阅读时可把 Grammar/ 看作语法定义来源,把 Parser/ 看作把 token stream 变成语法结构的实现区域。
贯穿示例从第一行 import json 开始就是文本。解释器需要把字符流拆成 token,再根据 grammar 识别 import statement、class definition、function definition、dict display、attribute access 和 call expression。tokenizer 解决“这段字符是什么 token”,parser 解决“这些 token 组成什么语法结构”,AST 入口解决“后续 compiler 能消费什么树形表示”。
class Box: 这一行能体现 parser 与 compiler 的边界。parser 识别 class statement 的语法形态,保留 class name、base list、decorator、body 和 source location;compiler 再决定 class body 如何变成 code object,runtime 再执行 class body 并调用 metaclass。语法结构只说明代码形状,执行语义要进入 Python/ 和 Objects/。
语法错误定位也属于 Parser/ 的观察范围。缺少冒号、括号不匹配、缩进与 token 流冲突时,错误通常在 parser 阶段被定位。运行时错误则发生在后续执行阶段,例如 Box(3).missing 这种 attribute error 已经越过 parser 和 compiler,进入对象查找和异常设置路径。定位错误类型时,先区分“文本无法形成语法结构”还是“语法合法但执行失败”。
源码阅读中常见误区来自把 grammar、AST、bytecode 混在一起。本章采用三层判断:Grammar/ 和 Parser/ 决定语法结构,Python/compile* 和 Python/symtable* 决定编译表示,Python/ceval* 执行字节码并分发到对象。三层之间的材料不同,结论也不同。
阅读 Parser/ 的稳定顺序是:先定位语法现象属于 token、grammar rule 还是 AST 节点;再确认错误发生在解析期、编译期还是执行期;接着把源码位置 metadata 放入错误信息和调试信息中理解;最后回到 Python/ 看 AST 如何进入 compiler。这样能把“语法长什么样”和“运行时做什么”拆开。
62.5 Modules/
Modules/ 放置 CPython 随发行版提供的 C 扩展模块、内置模块、平台相关模块和部分启动入口。它连接 Python 标准库的高层接口与 C 层实现能力。遇到“标准库函数为什么走 C 实现”“某个模块为什么依赖平台”“某个内置模块如何初始化”的问题,通常要进入 Modules/。
贯穿示例中的 json.dumps 首先是 Lib/json/ 下的 Python API。CPython 还提供 _json accelerator,用 C 实现部分编码和解码能力。阅读这种标准库路径时,应先从 Python 层入口理解 API 语义,再看是否存在同名或下划线开头的 C accelerator;进入 Modules/ 后,再找 PyInit_* 初始化函数、method table、module state 和参数解析。
Modules/ 中还有很多平台边界明显的实现。posixmodule.c、selectmodule.c、socketmodule.c、_ssl、_sqlite 等文件或子目录会把操作系统、第三方库和 Python 对象连接起来。阅读这些模块时,结论通常带有平台和构建选项边界;同一个 Python API 在不同平台上的可用能力、错误码和资源生命周期可能不同。
内置模块与 extension module 的初始化也能在 Modules/ 中观察。C 模块通常通过 module definition、method table、slot、module state 和 PyModuleDef 连接到 import system。多阶段初始化、per-interpreter module state 和异常返回约定会影响模块在 subinterpreter、reload、free-threaded runtime 中的行为。这里的细节会在后续 runtime evolution 中继续展开。
Modules/ 与 Lib/ 的关系是阅读标准库时的关键边界。Lib/ 常给出公开 API、组合逻辑和 fallback;Modules/ 常给出性能敏感、系统相关或二进制协议相关的 C 实现。一个标准库问题如果只涉及 Python 对象组合,可以停留在 Lib/;如果涉及速度、系统调用、buffer、文件描述符、SSL、压缩、哈希或编码器核心循环,就要进入 Modules/。
本地定位 C accelerator 可以用下面的命令。它回答“Python 层模块是否有对应 C 初始化入口”。
CPYTHON_SRC=/path/to/cpython
grep -R "PyInit__json" "$CPYTHON_SRC/Modules" "$CPYTHON_SRC/Lib/json"
读到 PyInit__json 后,下一步要看它注册了哪些函数、这些函数如何解析 Python 参数、如何创建返回对象、如何设置异常、是否释放临时引用。这个顺序把 C 模块阅读拉回前面几章已经建立的引用所有权和错误路径纪律。
62.6 Lib/
Lib/ 是 Python 实现标准库的主要目录。它展示标准库如何使用 Python 语言自身组织抽象:模块、类、函数、decorator、context manager、iterator、async abstraction、import hook、inspection 和 testing support。遇到“标准库 API 如何组合 Python 机制”的问题,通常要先读 Lib/。
贯穿示例中的 import json 会进入 Lib/json/ 的包结构。这里能看到公开函数如何组织参数,如何选择 encoder 或 decoder,如何在可用时接入 C accelerator,如何把 Python 对象转换成 JSON 文本。Lib/ 给出的解释更接近用户可见 API;Modules/ 给出的解释更接近性能和二进制边界。
Lib/importlib/ 是阅读 import system 的关键材料。CPython 启动时需要 import machinery 很早可用,因此 importlib 的一部分会作为 frozen module 参与 runtime bootstrap。用户层看到的是 import json,源码树中能看到 finder、loader、ModuleSpec、sys.modules cache、package path 和 source loader 等结构。这个例子说明 Lib/ 可以承载解释器核心机制的高层实现。
Lib/asyncio/、Lib/contextlib.py、Lib/inspect.py、Lib/dataclasses.py 等文件展示 Python 抽象如何建立在协议和对象模型上。context manager 依赖 __enter__ / __exit__,iterator 依赖 __iter__ / __next__,inspection 依赖 function、frame、code object 和 module metadata。阅读这些文件时,要把标准库代码放回本书前面建立的 object、frame、namespace 和 protocol 模型中。
Lib/test/ 也是源码阅读材料。测试不等同于规范文本,但测试能揭示边界条件、错误消息、平台分支和回归案例。阅读 CPython 行为变化时,源码、文档、NEWS 和测试应合并判断:源码说明实现路径,文档说明承诺边界,测试说明维护者希望保留的可观察行为。
阅读 Lib/ 时,稳定顺序是:先找公开 API 的 Python 层入口;再看它是否调用 private helper、协议方法或 C accelerator;接着识别缓存、fallback、平台分支和异常转换;最后把行为映射回语言模型。这样读标准库,能看到它如何复用 Python runtime 机制,而不会把标准库代码读成孤立脚本。
62.7 startup path
startup path 指 CPython 进程从可执行文件入口到执行用户代码之间的路径。它串起命令行解析、配置读取、path config、runtime 初始化、interpreter 创建、import bootstrap、main module 选择和脚本执行。贯穿示例中的 python app.py 在执行第一行 import json 之前,已经完成了大量 C 层和 runtime 状态准备。
在典型命令行运行中,入口会从程序层进入 CPython main 逻辑,再建立 PyConfig、解析命令行选项、设置 filesystem encoding、计算 module search path、初始化 runtime 和 interpreter。具体文件会随版本变化,但 Programs/、Modules/main.c、Python/initconfig.c、Python/pathconfig.c、Python/pylifecycle.c 是常见定位区域。阅读时应以当前版本源码为准。
path config 对 import json 有直接影响。解释器需要知道标准库目录、site-packages、当前工作目录、zip path、virtual environment 和环境变量对搜索路径的影响。用户层看到的是 sys.path;源码层要追踪配置解析和路径计算。定位 import 问题时,先看 startup path 是否正确建立路径,再看 importlib 的 finder 和 loader 是否命中目标模块。
main module 执行是 startup path 的收束点。python app.py、python -m package.module、交互式 REPL、-c 字符串、嵌入式调用都把不同输入包装成可执行代码。它们最终会进入 compile/run 相关路径,但输入来源、__name__、__package__、sys.argv 和当前目录处理会有差异。源码阅读时要先确认启动模式,再判断后续 import 和 module metadata。
startup path 也是 embedding 场景的边界。宿主程序可以通过 C API 初始化解释器、设置配置、执行代码、清理解释器。此时 stdout/stderr、signal、allocator、thread state 和错误返回需要映射回宿主系统。阅读嵌入式问题时,Python/pylifecycle.c 与配置相关文件比 ceval.c 更靠前。
一个稳定定位顺序是:先确认启动方式,再确认 PyConfig 和 path config,再确认 runtime/interpreter/thread state 是否建立,再确认 import bootstrap 是否可用,最后进入 main module 执行。这个顺序能解释“为什么同一段 Python 代码在脚本、-m、REPL、嵌入式环境中表现不同”。
62.8 runtime bootstrap
runtime bootstrap 指 CPython 在执行用户代码前建立最小运行时世界的过程。这个世界包括 runtime state、interpreter state、thread state、内置类型、builtins module、sys module、import system、exception machinery、allocator、GC 和初始模块表。startup path 关注“从进程入口走到哪里”,runtime bootstrap 关注“执行用户代码前必须先存在什么”。
贯穿示例第一行 import json 依赖很多已经完成的 bootstrap 结果。sys.modules 要存在,import machinery 要存在,builtins 中的 __import__ 要可用,module object 和 dict object 要可创建,Unicode 字符串要可表示模块名,异常对象要可报告导入失败。这些对象在用户代码开始前就形成了基础 runtime。
内置类型的建立是 bootstrap 的核心。object、type、dict、list、str、tuple、function、module、BaseException 等类型需要先处于可用状态,后续 Python 代码才能创建类、模块、函数和异常。这里会连接 Objects/ 的类型定义、Include/internal/ 的 runtime state 声明和 Python/ 的初始化流程。
builtins 与 sys module 是用户代码和解释器状态之间的桥。print 来自 builtins,sys.modules 保存 import cache,sys.path 承接路径配置,sys.argv 承接启动参数。print(json.dumps(payload)) 能运行,依赖这些模块在用户代码前被安装到 interpreter state 中。阅读 NameError、import cache 或启动配置问题时,builtins 和 sys module 经常是第一组证据。
import system 的 bootstrap 有特殊性。import machinery 本身需要导入模块,但早期解释器还没有完整 import 能力,因此 CPython 会使用 frozen importlib 等方式把关键 import 逻辑提前装入 runtime。这个过程把 Python/ 的 C 初始化、Lib/importlib/ 的 Python 实现和 frozen module 机制连接起来。阅读 import 启动问题时,应把“importlib 源码在哪里”和“它何时变成可执行模块”分开判断。
runtime bootstrap 的失败通常会表现为解释器启动失败、路径错误、编码初始化失败、内置模块缺失、frozen module 加载失败或 fatal error。用户代码异常通常还能形成 traceback;bootstrap 早期失败可能还没有完整异常展示能力。定位这类问题时,先看初始化阶段是否已经建立 thread state 和 exception machinery,再看错误是否能进入普通 Python 异常路径。
本章形成的最终源码树模型可以压缩成一句判断:CPython 先建立 runtime,再读取源码并构建语法结构,随后编译成 code object,在 frame 中执行 opcode,执行过程按对象类型和模块边界分发到 Objects/、Modules/ 和 Lib/,C 层边界由 Include/ 支撑。掌握这个顺序后,读者看到一个 Python 现象时,就能先定位目录,再选择合适的文件和函数继续阅读。
最小自检任务
阅读下面的代码,不打开 CPython 源码,先判断每个现象最应该进入哪个目录定位,并写出理由。
import json
class Counter:
def __init__(self):
self.value = 0
def step(self):
self.value += 1
return self.value
counter = Counter()
result = {"value": counter.step()}
print(json.dumps(result))
需要回答四个问题:第一,class Counter 和 counter.step() 分别涉及哪些对象层文件区域;第二,import json 应该如何在 Lib/、Modules/ 和 startup path 之间分层;第三,源码文本到可执行 frame 的路径经过哪些目录;第四,如果 json 找不到,应该先检查 path config、importlib、module object 还是 dict 实现。
答案要点
class Counter 首先定位到 Objects/。类创建、type object、method binding、实例属性和 descriptor lookup 都属于对象层;具体执行 class body 和调用函数时,还要进入 Python/ 的 frame 执行路径。counter.step() 会读取实例属性、绑定函数为 bound method、执行函数 body,并在 self.value += 1 中触发 attribute load、numeric operation 和 attribute store;对象行为看 Objects/,opcode 调度看 Python/。
import json 的公开 API 入口在 Lib/json/。如果 CPython 使用 _json accelerator,C 实现进入 Modules/。模块能否被找到还依赖 startup path 建立的 sys.path 和 runtime bootstrap 建立的 import machinery。因此 import 问题的分层顺序是:启动配置与路径、importlib 查找加载、module object 和 sys.modules cache、具体 Lib/ 或 Modules/ 实现。
源码文本先进入 Parser/ 形成 token、grammar 匹配和 AST 相关结构,再进入 Python/ 的 symbol table 与 compiler 路径生成 code object,随后在 Python/ 的 evaluation loop 中以 frame 为单位执行。执行中遇到 dict、str、class、function、module、exception 等对象时,再分发到 Objects/;遇到 C extension 时进入 Modules/;遇到 C API 声明、runtime state 字段或 slot 类型时进入 Include/。
如果 json 找不到,应先检查启动和路径配置,因为 import search path 决定 finder 能看到哪些位置;再检查 Lib/importlib/ 的查找加载路径和 sys.modules cache;随后检查 Lib/json/ 是否存在或被遮蔽;最后才需要看 dict 实现。dict 实现能解释 sys.modules 如何存储缓存,但它通常解释不了某个模块路径为何缺失。
本章知识点总结
- 源码地图:CPython 源码树可以按语法、执行、对象、模块、C API、启动和 bootstrap 七类问题定位。
- 对象目录:
Objects/承载 type、dict、unicode、function、descriptor 和 GC 参与对象的核心行为。 - 执行目录:
Python/承载编译、符号分析、frame 执行、异常传播、runtime 初始化和 import 底层支撑。 - 声明边界:
Include/用 public、CPython-specific、internal header 区分扩展入口和内部实现声明。 - 解析目录:
Parser/处理 token、PEG parser、AST 入口和语法错误定位,语法结构要和执行语义分层阅读。 - C 模块:
Modules/放置内置扩展、C accelerator、平台模块和系统相关能力。 - 标准库层:
Lib/展示标准库如何用 Python 代码组织 importlib、asyncio、contextlib、inspect 等高层抽象。 - 启动路径:startup path 串起命令行解析、配置、path config、runtime 初始化、import bootstrap 和 main module 执行。
- 运行引导:runtime bootstrap 在用户代码前建立内置类型、builtins、sys module、import system、thread state 和初始 interpreter state。
- 阅读顺序:源码阅读应先判断现象类别,再定位目录,然后追踪文件、结构体、slot、函数和错误路径。
- 版本边界:CPython 源码目录和文件会随版本演进,阅读本机行为时应选择与解释器一致的源码版本。
- 迁移判断:同类问题可按启动配置、语法解析、编译执行、对象分发、标准库实现和 C API 边界逐层排查。