用 6 个独立子进程真实验证 atexit:回调按注册的相反顺序执行、回调抛异常被打印并忽略且其余回调照常执行、在退出阶段再注册的回调不会执行、非守护线程会先被等完而守护线程被静默丢弃,unregister 会移除同一函数的所有注册。
本机真实建 zip 包放进 sys.path 导入:加载器是 zipimport.zipimporter,导入过程不会往 zip 里写 .pyc;相对 __file__ 打开包内数据文件抛 NotADirectoryError,pkgutil / importlib.resources 可以;zip 里的 .so 被忽略;同一 9000 行模块导入用时:目录 1.42 ms、zip 里放 .py 49.8 ms、zip 里放 .pyc 3.07 ms。
本机真实用 ast 解析源码:括号与注释都不在树里、优先级由树形状表达;统计 json/decoder.py 的 1759 个节点(48 种类型);用 NodeTransformer 把常量都加 1 后重新编译执行得到 39;literal_eval 拒绝函数调用而 eval 直接执行;编译器会常量折叠(2*3+1 直接变成 7)。
本机真实验证 compile 的 eval/exec/single 三种模式,exec 会往传入的字典里塞 __builtins__,在函数里 exec 写的变量读不到;空 __builtins__ 拦得住 print 却拦不住通过 object.__subclasses__() 找回 __import__(实测调用了 os.getpid());eval 字符串 6623 ns 而预编译 code 205 ns。
本机真实用 tokenize 切分源码:一行赋值被切成 8 个 token(含 COMMENT 和 NEWLINE);缩进以 INDENT/DEDENT token 表示;注释在 tokenize 里保留而在 ast 里不存在;f-string 在 3.12+ 被拆成 FSTRING_START/MIDDLE/END;括号内换行是 NL 而不是 NEWLINE;inconsistent 缩进 tokenize 不报错而 compile 报 IndentationError。
本机真实验证:两个对象互相引用后 del,弱引用仍然存活直到 gc.collect() 回收(4 个对象);gc 阈值 (2000, 10, 10);自己用 getrefcount 和 get_referents 实现「试探性删除」,判定的垃圾 [A, B, E] 与 gc.collect() 一致;20 万对环形垃圾在关闭 gc 时占用 70.4 MB,打开时仅 0.10 MB。
本机真实验证 gc.collect() 解决不了的四类内存问题:全局 cache 持有引用时回收 0 个(gc.get_referrers 直接找到持有者);gc.get_objects() 直方图看不到未追踪的 bytearray;回收 199999 个对象后 RSS 只从 280 MB 降到 246 MB;完整回收在 100 万个存活对象时要 12.0 ms,gc.freeze() 后降到 0.001 ms。
本机真实用 -X importtime 记录 python -c pass 启动时最外层导入的 7 个模块(site 一项累计 5434 µs);-S 让启动从 18.8 ms 降到 12.8 ms、模块数 54 → 21;实测用户 site-packages 的 .pth 里的 import 语句和 sitecustomize 会在主脚本之前执行,-I 与 -S 都能关掉它们。
本机真实验证 sys.path[0] 在 python 脚本 / -c / -m / 符号链接 / -P 下分别是什么;列出完整 sys.path 每一项来源;脚本目录里的 random.py 会遮蔽标准库(randint(1,100) 返回 4),json.py 里 import json 得到带改名建议的 AttributeError,os.py 因为已导入而无法遮蔽;300 次「先失败再创建再导入」在本机 0 次未找到。
本机真实验证 importlib:reload 之后模块对象 id 不变但 from 导入的旧值不更新、旧类的实例不再是新类的实例、已删除的名字残留;spec_from_file_location 能加载带连字符的文件且不进 sys.modules;find_spec 只查找不导入;LazyLoader 让 lazy() 返回 0.38 ms,首次访问属性才花 310 ms 执行模块。
本机真实对同一个文件分别用 python 文件 / python -m / import 三种方式运行:__name__、__package__、__spec__、sys.path[0] 和相对导入是否可用各不相同;a.py 与 b.py 互相导入会让 a.py 的顶层代码执行两次;定义在 __main__ 里的类 pickle 后在别处读取报 AttributeError;macOS 默认 spawn 下缺少 __main__ 保护会报 RuntimeError。
本机真实用 10 种方式结束一个 Python 进程,记录 atexit、finally、__del__ 和缓冲 print 是否执行:正常返回、异常、sys.exit、子线程异常、SIGINT、带 handler 的 SIGTERM 都执行,而 os._exit、os.abort、默认 SIGTERM、SIGKILL 全部不执行;SIGINT 的进程最终以信号 2 而不是退出码结束。