bigywater.tech
新版本特性 · 1

Python 3.15 lazy import 实测:导入 15 个标准库模块,启动从 100.3 ms 降到 19.4 ms,出错要等到第一次使用才报

“Python 3.15 的 lazy import 到底省多少启动时间、会不会让出错的位置变得更难找” 是升级前最该先测的新语法。这篇在本机用 Python 3.14.9 和 3.15.0 并排跑同一份代码,量出 15 个标准库模块的启动开销,复现出错时机的变化和不能写 lazy import 的位置,并试了不改代码的 -X lazy_imports=all。

100.3 → 19.4 ms
3.15 上导入 15 个标准库模块但一个都没用:普通 import 与 lazy import 的启动时间(空脚本 18.9 ms)
SyntaxError
lazy import 写在 try/except、函数、类里,或 lazy from … import *,编译期就拒绝
静默忽略
-X lazy_imports=all 在 Python 3.14 上不报错也不起作用

语法与基本行为

实测 · 本机执行输出
  Python 3.14(退出码 1):
        File "<tmp>/s1.py", line 3
          lazy import side
               ^^^^^^
      SyntaxError: invalid syntax
  Python 3.15(退出码 0):
      lazy import 之后: side 的类型 = lazy_import | 在 sys.modules 里: False
        [side.py 正在执行]
      第一次用 side.VALUE -> 7
      之后: side 的类型 = module | 在 sys.modules 里: True
  Python 3.15:lazy from … import(退出码 0):
      lazy from side import VALUE 之后,这行先执行
        [side.py 正在执行]
      第一次用 VALUE: 8

3.14 不认识 lazy import;3.15 里导入语句不执行模块,第一次用到名字时才导入,名字从 lazy_import 对象变成 module。

出错时机

实测 · 本机执行输出
  Python 3.15(退出码 1):
      lazy import 一个不存在的模块,这行照常执行
      Traceback (most recent call last):
        File "<tmp>/s4.py", line 2, in <module>
          lazy import no_such_module_xyz
      ImportError: lazy import of 'no_such_module_xyz' raised an exception during resolution
      
      The above exception was the direct cause of the following exception:
      
      Traceback (most recent call last):
        File "<tmp>/s4.py", line 4, in <module>
          no_such_module_xyz.f()
          ^^^^^^^^^^^^^^^^^^
      ModuleNotFoundError: No module named 'no_such_module_xyz'
  Python 3.15:sys.lazy_modules 与全局模式(退出码 0):
      lazy 导入之后 sys.lazy_modules 里有 side: True | 有 json: True
      sys.get_lazy_imports() = normal

不存在的模块在 lazy import 那一行不报错,第一次使用时才抛出,traceback 是 ImportError 链加 ModuleNotFoundError。

不能写的位置

实测 · 本机执行输出
  try / except 里(退出码 1):
      SyntaxError: lazy import not allowed inside try/except blocks
  函数里(退出码 1):
      SyntaxError: lazy import not allowed inside functions
  类里(退出码 1):
      SyntaxError: lazy import not allowed inside classes
  lazy from … import *(退出码 1):
      SyntaxError: lazy from ... import * is not allowed
  -X lazy_imports=all 时,try 里的普通 import(退出码 0):
      try 里的 import 立即报了 ImportError

try/except、函数、类里和 import * 是编译期 SyntaxError;全局 all 模式也不碰 try 里的普通 import。

全局开关

实测 · 本机执行输出
  -X lazy_imports=all(退出码 0):
      全局 all 模式下,普通 import side 之后在 sys.modules 里: False
      sys.get_lazy_imports() = all
  PYTHON_LAZY_IMPORTS=all(退出码 0):
      sys.get_lazy_imports() = all
      side 在 sys.modules 里: False
  Python 3.14 加 -X lazy_imports=all(退出码 0):
        [side.py 正在执行]
      x
  过滤器:side 不延迟(退出码 0):
        filter 被调用: __main__ side None
        [side.py 正在执行]
        filter 被调用: __main__ json None
      side 已导入: True | json 已导入: False

-X lazy_imports=all 或 PYTHON_LAZY_IMPORTS=all 不改代码就让顶层 import 变延迟;3.14 上这个选项被静默忽略;sys.set_lazy_imports_filter 可以排除个别模块。

启动时间

实测 · 本机执行输出
  写法                                        中位数 ms    最小 ms    最大 ms   启动后 sys.modules 里的模块数
  3.14 空脚本(基线)                                18.9     17.4     21.3   33
  3.15 空脚本(基线)                                18.9     17.3     20.9   33
  3.14 普通 import                              91.1     85.5    102.9   238
  3.15 普通 import                             100.3     92.6    109.3   242
  3.15 lazy import                            19.4     18.5     23.7   33
  3.15 lazy import 然后用到 json                  24.4     22.1     26.2   58
  3.15 普通 import + -X lazy_imports=all        18.9     17.2     28.2   33
  3.15 里 15 个模块的导入开销:普通 import 比空脚本多 81.4 ms,lazy import 比空脚本多 0.5 ms
  3.14 里 15 个模块的导入开销:普通 import 比空脚本多 72.1 ms

导入 15 个标准库模块但没用到:普通 import 比空脚本多约 81 ms,lazy import 只多 0.5 ms,代价是推迟到第一次使用。

分步演示

lazy import 实测
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Homebrew 的 Python 3.14.9 与 3.15.0(同一台机器上两个解释器并排跑同一份代码;两者都不是自由线程构建,也都没有启用 JIT);每个例子是临时目录里的独立小脚本,用子进程运行并取真实的 stdout / stderr(路径换成 );计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇所有例子都跑在同一台机器上的两个解释器上;启动时间用子进程反复启动同一份脚本,7 种写法交替运行 25 次(每种前 3 次丢弃),取中位数
    • 没有验证:真实应用(Django、Flask、命令行工具)里改成 lazy import 之后的整体启动时间;第三方库在 -X lazy_imports=all 下的兼容性;导入时有副作用(注册插件、改全局状态)的模块被推迟之后的行为差异;多线程里同时首次使用同一个 lazy 名字的并发行为;lazy import 对类型检查器、IDE、打包工具(PyInstaller 等)的影响;Python 3.15 的其他版本;PEP 810 的完整规范(本篇只验证了行为)
    京ICP备2026067502号-1京公网安备11010502063487号