知其然,知其所以然
Python 2026-09-29

CPython free-threading:去掉 GIL 后会改变什么

本机用 3.14 与自由线程版 3.14t 各跑同一个 CPU 密集任务:4 线程并行时 GIL 版加速比 1.00x、自由线程版 2.61x(8 线程 3.66x),设 PYTHON_GIL=1 后回到 1.23x;4 个线程各做 50 万次 += 1,GIL 版恒为 2000000,自由线程版只得到约 83 万。

Python CPython 并发 GIL 真实验证 动画演示
Python 2026-09-29

子解释器:多个 Python 解释器如何隔离

本机 Python 3.14 的 concurrent.interpreters 真实实验:子解释器的全局变量和 sys.modules 相互独立;Lock、文件不能跨解释器传,主脚本里定义的类也传不过去;4 份 CPU 密集任务下 InterpreterPoolExecutor 加速 2.86x、线程池 1.01x、进程池 2.22x;创建一个子解释器 8.7 ms,spawn 一个进程 48 ms。

Python CPython 并发 子解释器 真实验证 动画演示
Python 2026-09-29

ctypes:Python 如何调用 C 动态库

本机真实用 ctypes 调用 libc 与自己编译的 C 动态库:不声明 argtypes 时传 Python float 直接 ArgumentError,只声明 argtypes 不声明 restype 时 sqrt(2.0) 返回 0;malloc 默认返回值被截断成 32 位;结构体布局与 C 的 sizeof/offsetof 一致(24 字节);qsort 回调 Python 比较函数 17 次;对 100 万整数求和,C 函数 0.30 ms、sum() 3.0 ms、for 循环 53 ms;读空指针进程直接被 SIGSEGV 杀死。

Python 标准库 C扩展 ctypes 真实验证 动画演示
Python 2026-09-29

Python 构建系统:pyproject.toml 到底由谁执行

本机真实用一个自己写的最小 build backend(通过 backend-path 放在项目里,requires 为空)验证 pyproject.toml 的构建流程:python -m build 与 pip 作为前端,每个钩子都在一个独立的后端子进程里执行(pid 各不相同,父进程是前端),默认隔离环境使用临时 build-env 的 Python;pip 比 build 多调用 prepare_metadata_for_build_wheel;产出的 wheel 只是含 dist-info 的 zip。

Python 打包 PEP 517 真实验证 动画演示
Python 2026-09-29

Python entry points:命令行和插件是如何被发现的

本机在全新虚拟环境里真实安装一个项目:pip 把 [project.scripts] 变成 env/bin/hello-cli 几行启动脚本,把 entry-points 写进 dist-info/entry_points.txt;importlib.metadata.entry_points() 只读元数据、不导入代码,load() 才导入;手工放一个假 dist-info 就能「发现」不存在的插件;扫描成本随已安装包数增长(0 → 1600 个:3.5 → 70 ms)。

Python 打包 插件 真实验证 动画演示
Python 2026-09-29

editable install:pip install -e 到底改变了什么

本机在全新虚拟环境里对比普通安装与 pip install -e:普通安装拷贝一份代码、改源码不生效;可编辑安装只在 site-packages 放一个 __editable__ .pth(内容是项目 src 路径)和带 editable:true 的 direct_url.json,改源码立即生效、新增包也能 import;但新增命令行脚本必须重新安装;并用真实的 setuptools 后端复验同样结果。

Python 打包 pip 真实验证 动画演示
Python 2026-09-29

unittest discovery:测试框架如何找到 TestCase

本机造一棵测试目录树,真实验证 unittest discover 的规则:只导入文件名匹配 test*.py 的模块(strings_test.py、check_util.py 被忽略);没有 __init__.py 的子目录整个被跳过而且没有任何提示;导入失败的测试文件变成 _FailedTest 报 ERROR 而发现继续;只收集继承 TestCase 且以 test 开头的方法,同一个类里按方法名字母序执行;-k 过滤时导入失败仍会被报告。

Python 测试 unittest 真实验证 动画演示
Python 2026-09-29

pytest 参数化:一组测试如何覆盖几十种输入

本机 pytest 9.1.1 真实验证 @pytest.mark.parametrize:10 组参数生成 10 个独立用例,2 个失败都被精确报告(for 循环写法只报第一个);默认 id 对非基本类型退化为 x4、x5;叠加两个 parametrize 得到 3×4=12 的笛卡尔积;共享的可变参数在用例间是同一个对象;3000 个参数化用例总耗时 1.02 s、单个用例循环 0.30 s。

Python 测试 pytest 真实验证 动画演示
Python 2026-09-29

Hypothesis:基于属性的测试如何发现边界 bug

本机 hypothesis 6.168.3 真实测一个行程编码函数:手写 7 个例子全部通过,而 property「decode(encode(s)) == s」在第 7 个随机输入 Ö7 就失败并缩小到最小反例 "0";第一次「修复」排除 Nd 类别仍被发现 "²"(isdigit 为真但类别是 No)引起 ValueError;失败例子被记入 .hypothesis 数据库,第二次运行只调用 2 次就复现。

Python 测试 hypothesis 真实验证 动画演示
Python 2026-09-29

coverage.py:覆盖率数字到底说明了什么

本机 coverage 7.16.2 真实验证覆盖率的含义:一个只调用不断言的测试行覆盖 100%、行+分支覆盖 82%,却完全发现不了「会员订单价格变负」的 bug;补齐分支后仍是 100% 却仍无断言;没被 import 的文件默认不进报告(100% → 加 --source=. 后 73%);# pragma: no cover 直接改变数字;3 万行不同代码各跑一次时开销 54x(行)/145x(分支),反复跑的热循环几乎无开销。

Python 测试 coverage 真实验证 动画演示
Python 2026-09-29

tox 和 nox:如何测试多个 Python 版本

本机用 tox 4.64.4 和 nox 2026.8.17 在 Python 3.12.14 与 3.14.7 上跑同一份检查:py312 因为没有 annotationlib 和 t-string 语法失败、py314 通过,两者都各自建了虚拟环境(.tox/py312、.nox/tests-3-12 等);tox 首次 0.8 s、复用 0.2 s、-r 重建 0.5 s;nox 的 session 是 Python 函数,可以按 session.python 写条件。

Python 测试 tox nox 真实验证 动画演示
Python 2026-09-29

Ruff、Black 和 isort:Python 代码质量工具如何协作

本机真实对同一段乱序代码跑 black、isort、ruff:格式化与 import 排序是两件事,三者都不会删除未使用的 import(ruff 的 F401 才会报);isort 默认配置生成的网格式 import 会被 black --check 判失败,加 --profile black 后一致;ruff(I)+ruff format 与 isort+black 输出逐字相同;300 文件下 black 918 ms 对 ruff format 24 ms、isort 229 ms 对 ruff 26 ms。

Python 工程化 ruff black isort 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号