当代码使用 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_builtin
在 PyImport_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 451和 302 .关于内置模块的文档不多,尽管我确实找到了 a bit of documentation针对在其他程序中嵌入 Python 的人,因为他们可能想要修改 PyImport_Inittab
,并且有 sys.builtin_module_names
列表。
关于python - 导入语句在哪里/如何解析名称 `posix`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42707371/