【问题标题】:Why are so many modules initially loaded in CPython?为什么最初在 CPython 中加载了这么多模块?
【发布时间】:2022-09-23 09:06:21
【问题描述】:

python docs 状态:

一个完整的 Python 程序在最小初始化环境中执行:所有内置和标准模块都可用,但没有一个被初始化,除了sys(各种系统服务)、builtins(内置函数、异常和无)和__main__

这表明只有这三个模块应该被列为带有the following code snippet 的加载模块:

import sys
print(sys.modules.keys())

但是,使用 CPython v3.10 (with -S option) 运行代码 sn-p 会在我的 PC 上返回以下内容:

dict_keys([\'sys\', \'builtins\', \'_frozen_importlib\', \'_imp\', \'_thread\', \'_warnings\', \'_weakref\', \'_io\', \'marshal\', \'nt\', \'winreg\', \'_frozen_importlib_external\', \'time\', \'zipimport\', \'_codecs\', \'codecs\', \'encodings.aliases\', \'encodings\', \'encodings.utf_8\', \'encodings.cp1252\', \'_signal\', \'_abc\', \'abc\', \'io\', \'__main__\'])

与文档中提到的“最小初始化环境”相比,为什么在运行时加载了 22 个额外的模块?

我在下面用我自己的答案更新我对 CPython 的额外加载模块的理解。

  • 文档中没有任何内容表明您看到的输出,因为该描述是针对理论上可能存在的最简单的 Python。您可能通过 CPython 运行该代码,该 CPython 提供特定于实现的环境,由其 _frozen_importlib 的默认导入提供。在 pypy 实现中运行相同的代码将导致一些相同的键加上某些其他键。
  • @metatoaster 我已经更新了这个问题,专门询问 CPython 需要这么多包的原因。
  • 值得怀疑的是,除了文档未描述的实现细节之外,您还会得到一个具体的答案。如果这真的让你感到厌烦,我建议在 CPython 的issue tracker 提交问题。
  • 此外,您可以运行python -S -v -c \'\',它将打印出在启动期间导入的内容并运行一个空的 Python 程序。

标签: python python-module cpython


【解决方案1】:

到目前为止我发现了什么:

大多数额外模块都可以提供import 关键字功能和文本编码。

  • 在解释器初始化期间,通过导入 _frozen_importlib_imp 提供导入功能(在 pycore_interp_init 期间,在 init_importlib 内)
  • _setup() 在 importlib 的 _bootstrap.py 然后导入 _thread_warnings_weakref因为它们是在引导期间显式导入的内置模块,因此不是真正的额外模块.
  • 解释器初始化然后导入_frozen_importlib_external(在init_interp_main期间,在init_importlib_external内)
  • importlib 的 _bootstrap_external.py 导入了四个新的模块依赖项:_iomarshalntwinreg 包。如果不在 Windows 上,则导入 posix 而不是 ntwinreg
    • _io 已导入因为它是在引导期间显式导入的内置模块,因此不是真正的额外模块.
    • marshal 已导入因为它用于从 .pyc 文件加载/转储字节码.
    • nt/posix 被导入因为它用于操作系统功能,例如读取当前工作目录.
    • winreg 已导入因为它用于查找在 windows 注册表中声明的模块.
  • 作为导入_frozen_importlib_external的一部分,解释器初始化然后导入zipimport,大概是为了允许打开zip格式的python档案
    • 作为导入zipimport 的一部分,唯一的新依赖是导入的time 模块。唯一的用途是 time.mktime() “将 Zip 存档中的日期/时间值转换为与 .pyc 文件中存储的时间戳兼容的值”
  • _frozen_importlib_external 之后(因此在import 关键字功能被排序之后),解释器初始化然后导入encodings,大概是为了解码源文本。
    • encodings.aliases 已导入因为它提供了一个名称字典以映射到已知编码.
    • codecs 被导入,因为它是 encodings 的依赖项
      • _codecs是导入的,大概是因为是codecs的C版吧?
    • 然后导入encodings.utf_8,大概是因为它是默认编码。
    • 因为我们在 Windows 上,encodings.cp1252 也被导入(如果在 Linux 上,encodings.latin_1 被导入)。
  • 解释器初始化然后导入_signal,大概是为了解释器处理信号处理。
  • io 然后完全导入,大概是为了开源文件?
    • 然后导入abc,因为它依赖于io
      • 然后导入_abc,大概是因为是codecs的C版吧?
  • (在 Linux 上,readline 也被导入)

因此在使用 CPython 时会加载 22 个额外的“模块”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多