python - 导入语句在哪里/如何解析名称 `posix`?

标签 python linux python-import cpython

当代码使用 import posix 时,幕后发生了什么(在 CPython 3.6.0 中) ?此模块没有 __file__ 属性。在详细模式下启动解释器时,我看到了这一行:

import 'posix' # <class '_frozen_importlib.BuiltinImporter'>

它已经存在于新打开的解释器的 sys.modules 中,导入它只是将一个名称绑定(bind)到现有模块。

我正在尝试查看我平台上 os.lstat 的实现细节,以确定它是否以及何时使用 os.stat

最佳答案

在这里,提供比您可能需要的更多的详细信息。


posix 是一个内置模块。当您听到“内置模块”时,您可能会想到普通的标准库模块,或者您可能会想到用 C 编写的模块,但 posix 比大多数模块更内置。

posix 模块是用 C 语言编写的,在 Modules/posixmodule.c 中.然而,虽然大多数 C 模块,甚至是标准库 C 模块,都被编译为 .so.pyd 文件并像常规 Python 模块一样放置在导入路径中, posix 实际上直接编译到 Python 可执行文件本身。


CPython 导入系统的内部细节之一是 PyImport_Inittab array :

extern struct _inittab _PyImport_Inittab[];

struct _inittab *PyImport_Inittab = _PyImport_Inittab;

这是一个struct _inittab 数组,其中包含名称和具有该名称的模块的 C 模块初始化函数。此处列出的模块是内置的。

此数组最初设置为 _PyImport_Inittab,它来自 Modules/config.c(或 PC/config.c,具体取决于您的操作系统,但这里不是这种情况)。不幸的是,Modules/config.c 是从 Modules/config.c.in 生成的在 Python 构建过程中,所以我无法向您显示源代码链接,但这是我生成文件时的部分内容:

struct _inittab _PyImport_Inittab[] = {

        {"_thread", PyInit__thread},
        {"posix", PyInit_posix},
        // ...

如您所见,posix 模块有一个入口,还有模块初始化函数 PyInit_posix


作为导入系统的一部分,当尝试加载模块时,Python 会通过 sys.meta_path,模块列表 finders .其中一个查找器负责执行您可能更熟悉的 sys.path 搜索,但另一个查找器是 _frozen_importlib.BuiltinImporter,负责查找内置-在像 posix 这样的模块中。当 Python 尝试该查找器时,它会运行查找器的 find_spec。方法:

@classmethod
def find_spec(cls, fullname, path=None, target=None):
    if path is not None:
        return None
    if _imp.is_builtin(fullname):
        return spec_from_loader(fullname, cls, origin='built-in')
    else:
        return None

它使用 _imp.is_builtinPyImport_Inittab 中搜索 "posix" 名称。搜索找到名称,所以 find_spec 返回一个模块规范,表示内置模块的加载器应该处理创建这个模块的事实。 (加载器是 spec_from_loader 的第二个参数。这里是 cls,因为 BuiltinImporter 既是查找器又是加载器。)

Python 然后运行加载程序的 create_module生成模块对象的方法:

@classmethod
def create_module(self, spec):
    """Create a built-in module"""
    if spec.name not in sys.builtin_module_names:
        raise ImportError('{!r} is not a built-in module'.format(spec.name),
                          name=spec.name)
    return _call_with_frames_removed(_imp.create_builtin, spec)

委托(delegate)给_imp.create_builtin ,它在 PyImport_Inittab 中搜索模块名称并运行相应的初始化函数。

(_call_with_frames_removed(x, y) 只是调用 x(y),但 part of the import system 将其视为剥离 importlib 来自堆栈跟踪的帧,这就是为什么当您的导入出错时您永远不会在堆栈跟踪中看到这些帧。)


如果想看更多涉及的代码路径,可以翻看Lib/importlib/_bootstrap.py ,大部分导入实现所在的位置,Python/import.c ,实现的大部分 C 部分所在,以及 Python/ceval.c ,这是字节码解释器循环所在的地方,因此也是 import 语句开始执行的地方,在它到达导入机制的更核心部分之前。

相关文档包括 section of the language reference on the import system ,以及 PEP 451302 .关于内置模块的文档不多,尽管我确实找到了 a bit of documentation针对在其他程序中嵌入 Python 的人,因为他们可能想要修改 PyImport_Inittab,并且有 sys.builtin_module_names列表。

关于python - 导入语句在哪里/如何解析名称 `posix`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42707371/

相关文章:

python - 如何从不同的文件调用方法而不在python中导入它

c++ - 作为初学者了解 C++ 中的预处理器指令

python - 将 defaultdicts 的 iterable 连接到 DataFrame

python - python azure函数中的错误404 HEAD依赖性

Python Selenium WebDriver - 可以监视 XHR AJAX 调用吗?

linux - 如何在 Linux 上关闭 GPU 设备的 "REAL"PCIe 电源

python - 没有适用于 Linux 的 lxml Wheel?

linux - 根 shrc 的权限被拒绝

java - 是否有 Linux 命令来打印正在运行的 Java 进程的当前堆栈

python - 将 GPU 与 python 包 bert_embeddings 和 mxnet 一起使用失败