【问题标题】:importlib._bootstrap and python interpreter initializationimportlib._bootstrap 和 python 解释器初始化
【发布时间】:2019-02-06 14:13:36
【问题描述】:

CPython解释器模块导入系统是用python本身编写的,并在importlib._bootstrap中初始化。它的来源可以在importlib/_bootstrap.py 中看到,但它不是从那里加载的。相反,它是从所谓的冻结模块中加载的,该模块的字节码是baked 到解释器库(python37.dll)中。

解释器通过importing _frozen_importlib (it's a name for importlib._bootstrap baked into the interpreter)calling _install function defined there, passing sys and _imp modules as arguments 初始化自己。 _install 调用 _setup,初始化此模块所需的运行时,然后添加 2 个导入器,实现 PEP 451

在开发自定义导入器时,我在_bootstrap.py 或我的导入器中遇到了几个错误,因此我需要在_bootstrap.py 中添加一些调试输出。

所以我尝试让解释器从磁盘加载_bootstrap.py,而不是从烘焙的字节码中加载。

对 cpython 源代码的分析表明,为了导入内置模块,我不需要大部分 spec 类。所以内置模块可以使用_create_builtin导入

class UltraSimpleSpec:
    __slots__=("name",)
    def __init__(self, name):
       self.name = name

def _install(sys, _imp):
    io = _imp.create_builtin(UltraSimpleSpec("_io"))
    _bi = _imp.create_builtin(UltraSimpleSpec("builtins"))
    fd = io.open("path/to/_bootstrap.py", "rt") # exits the _install function without any exception, how can it do it?
    raise _bi.Exception("Never called") # _bi.print doesn't work, because sys.stdout is not initialized, so I have to use exceptions for debug output
    ...

不幸的是,发生了一些奇怪的事情,调用 io.open 导致_install 退出,控制流永远不会到达下一条语句。而且似乎没有引发异常,当它出现时,解释器会打印它,而是由于缺少_install 的副作用而在另一个地方引发异常。

还有一个麻烦是sys.stdout 没有初始化,所以我们不能print 并且不得不依赖异常来调试输出。

所以

  1. 我应该如何让open 工作?

  2. 我应该如何初始化sys.stdout

【问题讨论】:

  • 我很想知道你在“_bootstrap.py”中遇到的那些错误,即使在像wasm或android这样奇怪的平台上也不需要修改它。你想达到什么目标?
  • IDK 暂时(尚未调试它,很忙),但在与我的自定义模块加载器交互时它会中断。 1 importlib.reload 不起作用。 2.当我用my custom loader, wrapping importlib.import_module加载一个模块时,当我稍后加载该模块的一个子模块时,我得到一个模块不存在的错误。
  • 您可能需要在使用重载或插件系统之前调用 importlib.invalidate_caches()。

标签: python python-3.x initialization cpython


【解决方案1】:

不是一个完整的答案,但我只为我的案例解决了一个问题(加载 python 源代码)。

我应该如何让open 工作?

原来那个时候字符串编码不可用,所以我用rb代替r。然后我把bytes传给compile,就可以处理了。

【讨论】:

  • 我认为您可能需要import _bootlocale 在挂钩导入系统和/或在启动环境中使用 PYTHONUTF8=1 之前。有可能使用文本 iowrappers + getpreferredencoding 进行循环导入。我认为它已在 3.10 中修复。 (参见github.com/python/cpython/blob/3.9/Lib/locale.py#L658
  • 感谢您的建议。我查看了cpython源代码,看到_bootlocale是通过PyImport_ImportModule导入的,它调用PyImport_Import,它调用__import__。因此,在正常操作中,导入系统必须在导入 _bootlocale 时已经运行。
猜你喜欢
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 2011-12-06
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 2017-11-29
相关资源
最近更新 更多